久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 5435|回復(fù): 4
收起左側(cè)

基于安卓經(jīng)典藍(lán)牙開(kāi)發(fā)-串口 附源碼

  [復(fù)制鏈接]
ID:413056 發(fā)表于 2020-11-28 17:15 | 顯示全部樓層 |閱讀模式
  • 展現(xiàn)廣播的三種方式
  • 通知; 2、對(duì)話框; 3、消息提示框
  • 在使用Android藍(lán)牙適配器中的startDiscovery需要先打開(kāi)定位服務(wù)
  • 在連接藍(lán)牙之前,還要先取消藍(lán)牙設(shè)備的掃描,否則容易連接失敗
前段時(shí)間自己學(xué)做了一個(gè)基于安卓經(jīng)典藍(lán)牙的app,也遇到不少坑,在網(wǎng)上相對(duì)與BLE低功耗藍(lán)牙來(lái)說(shuō),它的資料方面都是比較缺少的,而且網(wǎng)上經(jīng)典藍(lán)牙源碼大部分都很長(zhǎng),對(duì)于入門(mén)的同學(xué)來(lái)說(shuō),看沒(méi)兩分鐘就產(chǎn)生放棄的念頭了。
第一步:在AndroidManifest中添加:
<!--管理藍(lán)牙需要-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--搜索藍(lán)牙需要,因?yàn)樗{(lán)牙可以被用來(lái)定位,所以需要定位權(quán)限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
上面都是我們使用到設(shè)備功能的權(quán)限申請(qǐng)。
第二步:設(shè)置兩個(gè)按鈕分別是打開(kāi)和關(guān)閉藍(lán)牙
對(duì)藍(lán)牙設(shè)備干事情,那么我們就得拿到它的接口來(lái)控制它
//獲取藍(lán)牙適配器
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
打開(kāi)藍(lán)牙:
1、
public void OpenBlueTooth(View view) {
    if(isSupportBlueTooth() == true) {
        if(!BlueToothState()) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent,0);
            showToast("親,打開(kāi)了噢!需要什么幫助嗎?");
        }
        else {
            showToast("親,已經(jīng)打開(kāi)了噢,無(wú)需重復(fù)打開(kāi)。");
        }
    }
    else {
        showToast("親,您不支持此藍(lán)牙設(shè)備!");
    }
}
2、打開(kāi)藍(lán)牙應(yīng)該先確定使用的手機(jī)是否支持藍(lán)牙設(shè)備(手機(jī)沒(méi)有就沒(méi)必要進(jìn)行下一步了)
//判斷是否支持藍(lán)牙
public boolean isSupportBlueTooth() {
    if(mBluetoothAdapter != null) {
        return true;
    }
    else {
        return false;
    }
}
3、然后打開(kāi)前還需要知道手機(jī)是否打開(kāi)藍(lán)牙了吧!那就獲取手機(jī)現(xiàn)在藍(lán)牙設(shè)備的狀態(tài)
//獲取藍(lán)牙狀態(tài)
public  boolean BlueToothState() {
    assert (mBluetoothAdapter != null);   //若不支持該藍(lán)牙設(shè)備會(huì)有個(gè)斷言
    return mBluetoothAdapter.isEnabled();  
}
2、3小步驟都只是個(gè)函數(shù)功能體,都是為1、步驟使用的,初學(xué)者會(huì)疑惑什么是斷言,就是做判斷,真的那么下面就不執(zhí)行咯!還有下面是是一個(gè)消息對(duì)象,
獲取用戶對(duì)藍(lán)牙適配器申請(qǐng)打開(kāi)的請(qǐng)求消息,使用startActivityForResult對(duì)消息做出應(yīng)答,會(huì)有對(duì)話框的提示效果
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent,0);
關(guān)閉藍(lán)牙:
public void CloseBlueTooth(View view) {
    mBluetoothAdapter.disable();
    showToast("親,我們會(huì)再見(jiàn)面的!");
}
先說(shuō)明一點(diǎn)我這里的還是都在有View view形參接口,這是一個(gè)動(dòng)作的監(jiān)聽(tīng)接口,下圖有設(shè)置的圖片,這里設(shè)置就可以了。

感覺(jué)打開(kāi)藍(lán)牙和關(guān)閉藍(lán)牙挺簡(jiǎn)單的吧!
難度開(kāi)始來(lái)了噢!

第三步:
打開(kāi)了藍(lán)牙我們就得弄一個(gè)來(lái)搜索周圍的設(shè)備吧!
下面是一個(gè)定義好的搜索藍(lán)牙函數(shù)
public void startDiscovery() {
    if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery();  Toast.makeText(this,"搜索器打開(kāi)",Toast.LENGTH_SHORT).show();}
    mBluetoothAdapter.startDiscovery();
    if (!mBluetoothAdapter.isDiscovering()) {Toast.makeText(this,"搜索器沒(méi)打開(kāi)",Toast.LENGTH_SHORT).show();}
}
有點(diǎn)看不懂嗎,其實(shí)還好吧,就是第一次判斷是否開(kāi)啟搜索周圍藍(lán)牙設(shè)備,開(kāi)啟了就把它關(guān)了,重新打開(kāi)在搜索,在判斷我是否開(kāi)啟了搜索沒(méi)。(isDiscovery是開(kāi)啟搜索,cancelDiscovery是關(guān)閉搜索的意思)
有搜索藍(lán)牙設(shè)備函數(shù)了,我們就搞一個(gè)按鍵讓其有觸發(fā)效果吧!
//按鈕搜尋藍(lán)牙
Button button_discovery = (Button) findViewById(R.id.DiscoveryBT);
button_discovery.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        startDiscovery();
    }
});
開(kāi)啟了搜索藍(lán)牙設(shè)備我們得有東西接收這些設(shè)備吧,不然它偷偷摸摸搜索鬼知道它搜了什么東西。那我們就得用廣播把這些偷偷摸摸搜索到了設(shè)備把它弄出來(lái),放進(jìn)“箱子”里。
這就是我們定義的廣播接收器
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
            Toast.makeText(context, "開(kāi)始", Toast.LENGTH_SHORT).show();
        } else if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            //////////////////////////////////////////////創(chuàng)建搜索藍(lán)牙列表的///////////////////////////////////////////////////////////////////
            for (int i = 0; i < deviceAdress.size(); i++) {
                if (deviceAdress.get(i).getAddress().equals(device.getAddress())) return;
                //上面if語(yǔ)句就是去除已經(jīng)獲取的藍(lán)牙設(shè)備
            }
            // 不是重復(fù)的就添加到列表中(獲取未配對(duì)的藍(lán)牙設(shè)備)
            deviceAdress.add(device);  //添加地址到列表中   用于鑒別是否已經(jīng)添加列表和點(diǎn)擊事件用的
            deviceName.add("地址:"+device.getAddress()+"\n"+"名稱:"+device.getName());  //存放藍(lán)牙名稱和地址用于顯示到列表上的

        } else if(intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
        }
    }
}
代碼都有注釋我就不一一說(shuō)明了,說(shuō)一下箱子要在外面定義
public ArrayList<BluetoothDevice> deviceAdress = new ArrayList<>();  //存放藍(lán)牙設(shè)備(這里Adress我忘了改過(guò)來(lái)了,這是存放設(shè)備不是設(shè)備地址)
public ArrayList<String> deviceName = new ArrayList<>();  //存放藍(lán)牙名稱和地址
然后就是用廣播類里面用if那些進(jìn)行信息篩選(用藍(lán)牙設(shè)備這個(gè)方法獲取設(shè)備的信息BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE
然后就是把搜索到的device
你可以用Toast.make()打印一下信息看看效果
記得廣播接收器的使用一定要注冊(cè)廣播接收器,不然就廢掉了
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//發(fā)現(xiàn)藍(lán)牙
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索停止
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED );//搜索啟動(dòng)
//上面是添加動(dòng)作事件
//注冊(cè)廣播接收者的對(duì)象
registerReceiver(myReceiver,intentFilter);
都放在箱子里了,我們應(yīng)該把它拿出來(lái)一個(gè)一個(gè)展示一下吧!
這展示的方法就是用列表把它展示出來(lái):
public ListView listView;   //定義展示列表

//////////////////////////////////////////////創(chuàng)建搜索藍(lán)牙列表的///////////////////////////////////////////////////////////////////并把
arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_expandable_list_item_1,deviceName);  //實(shí)例化ArrayAdapter對(duì)象deviceName集合數(shù)據(jù)放入arrayAdapter適配器集合內(nèi)
listView = (ListView) findViewById(R.id.list);  //獲取列表框的
listView.setAdapter(arrayAdapter);  //將arrayAdapter集合內(nèi)的數(shù)據(jù)加載到列表框 就是適配器對(duì)象與ListView關(guān)聯(lián)
這樣放進(jìn)列表你以為就可以了嗎,你怎么知道它加載了多少個(gè)已發(fā)現(xiàn)的設(shè)備呢?這需要我們到廣播接收器這個(gè)線程中間斷刷新載入新設(shè)備
arrayAdapter.notifyDataSetChanged();  //更新列表
下面是我定義的一個(gè)刷新列表搜索
        Button button= (Button) findViewById(R.id.Broadcast);  //獲取布局文件中的廣播按鈕
        button.setOnClickListener(new View.OnClickListener() { //為按鈕設(shè)置單擊事件
            @Override
            public void onClick(View v) {
                //////////藍(lán)牙刷新///////////////
                deviceAdress.clear();         //
                deviceName.clear();           //
                startDiscovery();             //
                ////////////////////////////////
            }
        });
到現(xiàn)在你就可以試試你做的可不可以將搜索到的藍(lán)牙加載到列表中顯示了,可以的化,看看可不可以刷新列表。

第四步:
把我們列表中的設(shè)備能進(jìn)行點(diǎn)擊觸發(fā)
    //連接藍(lán)牙
    public void Connect_BT(ArrayList<BluetoothDevice> deviceAdress) {
        //MainActivity 實(shí)現(xiàn)OnItemClickListener 然后重寫(xiě)方法
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                BluetoothDevice clickDevice = (BluetoothDevice)deviceAdress.get(position);
                String s1 = String.valueOf(position);  //編號(hào)
                Toast.makeText(MainActivity.this, s1 + "--" + clickDevice.getName() + "--" + clickDevice.getAddress(),Toast.LENGTH_SHORT).show();
                //在連接前需要先關(guān)閉搜索
            }
        });
    }
把我們列表按鍵觸發(fā)這個(gè)類放到廣播接收器這個(gè)線程中
Connect_BT(deviceAdress);
按下列表就有這個(gè)提示框咯!開(kāi)心吧

第五步:
連接我們選中的藍(lán)牙
連接這些藍(lán)牙都需要協(xié)議的,都是廠家底層工作人員定好的
//手機(jī)連接的UUID
//設(shè)備連接的UUID由廠商決定。
private final String BLUETOOTH_UUID = "00001101-0000-1000-8000-00805F9B34FB";   //藍(lán)牙通信的UUID,必須為這個(gè),如果換成其他的UUID會(huì)無(wú)法通信
private BluetoothSocket bluetoothSocket = null;
UUID我就步詳細(xì)說(shuō)了,你們自行百度。BluetoothSocket套接字就是連接藍(lán)牙服務(wù)器用的。
在Connect_BT添加下面代碼即可()
                //在連接前需要先關(guān)閉搜索
                //點(diǎn)擊列表,去請(qǐng)求服務(wù)器
                if (clickDevice != null) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                bluetoothSocket = clickDevice.createRfcommSocketToServiceRecord(UUID.fromString(BLUETOOTH_UUID));
                                bluetoothSocket.connect();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }).start();
                }
這我要說(shuō)明一下connect方法會(huì)阻塞線程,我們需要在下面創(chuàng)建一個(gè)子線程來(lái)運(yùn)行,不然程序奔潰別找我就可以了。
到這我們就所有基本弄好了

第五步:
接收和發(fā)送數(shù)據(jù)
這里我略微講一下
// 用來(lái)收數(shù)據(jù)
InputStream inputStream = bluetoothSocket.getInputStream();
// 用來(lái)發(fā)數(shù)據(jù)
OutputStream outputStream;
下面是我用按鍵發(fā)送數(shù)據(jù)的代碼(參考)
Button button_oc3 = (Button) findViewById(R.id.button_open_close3);
button_oc3.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        String text = "d12";
        try {
            outputStream = bluetoothSocket.getOutputStream();
            outputStream.write(text.getBytes());
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
});
記住完成BluetoothSocket的一系列操作后,記住用close()方法關(guān)閉套接字噢,不然手機(jī)很耗電,燒壞別找我麻煩。
接收數(shù)據(jù)的話會(huì)比較麻煩一點(diǎn)點(diǎn),需要用一個(gè)線程和while死循環(huán)繼續(xù)時(shí)刻接收(因?yàn)镮nputStream 也會(huì)阻塞線程的)

到這就告一段落了。
我有一個(gè)老師是這樣說(shuō)過(guò)的游戲打累了就休息一下,休息的方法就是敲代碼。

在社會(huì)學(xué)到的要學(xué)會(huì)分享回報(bào)社會(huì)

(有什么好的想法和建議可以分享一下給我)
廣州大學(xué)華軟軟件學(xué)院djw
51hei.png
全部資料51hei下載地址(源碼):
mybluetooth_finish.zip (412.24 KB, 下載次數(shù): 64)
經(jīng)典藍(lán)牙開(kāi)發(fā)過(guò)程.docx (148.04 KB, 下載次數(shù): 56)

評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:882411 發(fā)表于 2021-2-3 22:07 來(lái)自觸屏版 | 顯示全部樓層
樓主,這個(gè)是用eclipse編寫(xiě)的嘛
回復(fù)

使用道具 舉報(bào)

ID:413056 發(fā)表于 2021-3-22 20:37 | 顯示全部樓層
思慶 發(fā)表于 2021-2-3 22:07
樓主,這個(gè)是用eclipse編寫(xiě)的嘛

android studio
回復(fù)

使用道具 舉報(bào)

ID:368534 發(fā)表于 2021-4-7 17:45 | 顯示全部樓層
感謝樓主的無(wú)私奉獻(xiàn),文件可以打開(kāi),可以生成APK,內(nèi)容也很通俗易解。有參考價(jià)值。
回復(fù)

使用道具 舉報(bào)

ID:298011 發(fā)表于 2023-12-27 11:28 | 顯示全部樓層
寫(xiě)得很詳細(xì),學(xué)習(xí)下。
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 亚洲一区二区久久 | 夜夜狠狠擅视频 | 天堂一区二区三区 | 伊人久久av| 国产一区二区中文字幕 | 日韩欧美国产综合 | 日韩欧美一区二区三区久久婷婷 | 欧美日韩国产成人 | 黄色三级视频在线观看 | 狠狠干夜夜 | 天天精品 | 黄色三级网 | 免费毛片在线播放 | 亚洲精品www久久久久久广东 | 日韩专区在线观看 | 亚洲一区国产 | 久草福利资源 | 欧美视频三区 | 欧美另类综合 | 最新av在线 | 日韩三级影院 | 91小视频在线观看 | 日韩免费视频一区二区 | 久草小视频 | 张津瑜国内精品www在线 | 亚洲第一在线 | 欧美成人精品一区二区三区 | 天天干天天舔 | 两性午夜视频 | 欧美日韩国产激情 | 在线播放av网站 | 日韩免费精品视频 | 免费看黄色大片 | 免费一级a毛片 | 99久久精品国产一区二区三区 | 日本久久一区二区 | 天天爽天天 | 情侣av| 性欧美精品 | 国产视频一二区 | 日韩欧美在线观看视频 |