Android實(shí)現(xiàn)一對(duì)一藍(lán)牙聊天APP
學(xué)習(xí)了,三天的Android 藍(lán)牙開(kāi)發(fā),開(kāi)始是一頭霧水,看著別人講的Google官方的demo感覺(jué)很容易,所有自己也嘗試寫一個(gè)很簡(jiǎn)單的聊天demo.可是想的很簡(jiǎn)單,自己做起來(lái)也花了,將近一天的時(shí)間才搞定這個(gè)基本的流程設(shè)計(jì).下面是幾點(diǎn)心得后面再貼代碼
1)寫一個(gè)簡(jiǎn)單的demo也好,記得一定需要有總體的流程,才開(kāi)始摳代碼
2)既然是demo畢竟就是新的知識(shí),代碼中間的log點(diǎn)一定\不能少,這是你快速調(diào)試的利器
3)還是thinking in java 里面的那句話,思考什么是可變的,什么是不可變的,然后分開(kāi),這樣來(lái)實(shí)現(xiàn)代碼的封裝,感覺(jué)很不錯(cuò)了.只是現(xiàn)在感覺(jué)還是很難想明白
4)開(kāi)始思考以面向?qū)ο蟮牧鞒烫幚韱?wèn)題,需要怎么弄,也是封裝代碼的一種思想
藍(lán)牙聊天的基本功能:
1.實(shí)現(xiàn)一對(duì)一藍(lán)牙連接
2.實(shí)現(xiàn)一對(duì)一聊天
很簡(jiǎn)單的功能,思路看著也很清晰,可是深入去寫,才知道,水還是深度的,java不熟的話.
此處基本的如何打開(kāi)藍(lán)牙不在復(fù)述,請(qǐng)自行百度.
思路:
1)初始化,打開(kāi)手機(jī)的藍(lán)牙,開(kāi)始藍(lán)牙服務(wù)器線程,等待連接
2)配對(duì),獲取某臺(tái)手機(jī)的藍(lán)牙address地址.
3)開(kāi)啟連接線程連接手機(jī)藍(lán)牙
4)連接成功后,開(kāi)啟,藍(lán)牙聊天的線程,進(jìn)行聊天的通訊.
上面四步是主要思路,其中存在著幾個(gè)細(xì)節(jié)的地方,就是在開(kāi)發(fā)中某些邏輯問(wèn)題,線程間的安全問(wèn)題,也是需要好好處理的. 讓我感受比較深的地方是,一對(duì)一聊天,相當(dāng)于,首相每臺(tái)機(jī)器都可能作為服務(wù)器在進(jìn)行通訊,所以一開(kāi)始開(kāi)啟了兩個(gè)服務(wù)監(jiān)聽(tīng),一旦有一個(gè)接入進(jìn)來(lái),這里需要弄清楚哪個(gè)是接入對(duì)象,哪個(gè)是被接入對(duì)象, 沒(méi)有作為服務(wù)端的,可以把服務(wù)端線程關(guān)閉掉。
下面貼點(diǎn)代碼
/** * 客戶端啟動(dòng)連接線程 * 通過(guò)藍(lán)牙的mac地址獲取連接 * @author Administrator * */ private class ConnectThread extends Thread { private BluetoothDevice mDevice; private BluetoothSocket btSocket = null; public ConnectThread(String address) { // TODO Auto-generated constructor stub mDevice = mBluetoothAdapter.getRemoteDevice(address); } @Override public void run() { // TODO Auto-generated method stub connect(mDevice); } private void connect(BluetoothDevice btDev) { Method creMethod; try { creMethod = BluetoothDevice.class.getMethod("createBond"); creMethod.invoke(btDev); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } try { btSocket = btDev.createRfcommSocketToServiceRecord(MYUUID); System.out.println("========" + "start connect"); Log.d("BlueToothTestActivity", "開(kāi)始連接..."); btSocket.connect(); mClientSocket = btSocket; isConnected=true; mHandler.sendEmptyMessage(SUCCESS_SERVICE_BEGIN_TALKING); // 作為客戶端 關(guān)閉 服務(wù)端 等待的鏈接 if (acceptThread != null) { acceptThread.close(); } startTalk(); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("???????????????? close socket"); close(); System.out.println(e.toString()); e.printStackTrace(); } } private void close() { if (btSocket != null) { try { btSocket.close(); mHandler.sendEmptyMessage(FAILED_SERVICE_SOCRCKET); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } }
/** * 服務(wù)端的設(shè)計(jì) * 每個(gè)藍(lán)牙的客戶端先要開(kāi)啟服務(wù)端等待接入 * @author Administrator * */ private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; public AcceptThread() { // Use a temporary object that is later assigned to mmServerSocket, // because mmServerSocket is final BluetoothServerSocket tmp = null; try { // MY_UUID is the app's UUID string, also used by the client // code tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("Fisrt", MYUUID); } catch (IOException e) { mHandler.sendEmptyMessage(FAILED_SERVICE_SOCRCKET); } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; // Keep listening until exception occurs or a socket is returned while (isRun) { try { socket = mmServerSocket.accept(); mHandler.sendEmptyMessage(SUCCESS_SERVICE_SOCRCKET); Log.e("TAG", "========== server start ===="); } catch (IOException e) { mHandler.sendEmptyMessage(FAILED_SERVICE_SOCRCKET); close(); } // If a connection was accepted if (socket != null) { // 服務(wù)端連接成功,啟動(dòng)聊天線程,通過(guò) 同一個(gè) socket 防止多線程賦值出現(xiàn)空值的問(wèn)題 isConnected=true; mClientSocket = socket; mTalkThread = new TalkThread(); mTalkThread.start(); // Do work to manage the connection (in a separate thread) // 多線程操作小心不安全性 synchronized (BlueConnectService.this) { //close(); } } } } public void close() { isRun = false; try { mmServerSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
/** *設(shè)計(jì)連接成功后的聊天線程 1.建立流,打通連接 2.發(fā)送和接收數(shù)據(jù) 3.顯示數(shù)據(jù) *需要注意的是聊天的時(shí)候,需要同一個(gè)socket建立連接才能獲取對(duì)應(yīng)的輸入輸出流 */ private class TalkThread extends Thread { private final BluetoothSocket talkSocket; private final InputStream mIs; private final OutputStream mOs; private boolean isRunning = true; public TalkThread() { // TODO Auto-generated constructor stub talkSocket = mClientSocket; if (talkSocket == null) { System.out.println("================= talkThread erro "); // return; } InputStream is = null; OutputStream os = null; try { is = talkSocket.getInputStream(); os = talkSocket.getOutputStream(); } catch (IOException e) { // TODO Auto-generated catch block try { System.out.println("???????????????? close socket"); talkSocket.close(); CloseUtil.closeStream(is, os); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } e.printStackTrace(); } mIs = is; mOs = os; } @Override public void run() { // TODO Auto-generated method stub super.run(); byte[] buffer = new byte[1024]; int len; while (isRunning) { try { len = mIs.read(buffer); mHandler.obtainMessage(READ_MESSAGE, len, -1, buffer).sendToTarget(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); try { isRunning = false; isConnected=false; System.out.println("???????????????? close socket"); talkSocket.close(); // 需要重啟服務(wù)器 // 啟動(dòng)服務(wù)器 } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } CloseUtil.closeStream(mIs, mOs); } } } public void write(byte[] bytes) { try { mOs.write(bytes); mHandler.obtainMessage(WRITE_MESSAGE, bytes.length, -1, bytes).sendToTarget(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
關(guān)于AndroidStudio新建與編譯項(xiàng)目速度慢解決辦法
這篇文章主要介紹了關(guān)于AndroidStudio新建與編譯項(xiàng)目速度慢的解決辦法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10Android實(shí)現(xiàn)多個(gè)連續(xù)帶數(shù)字圓圈效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)多個(gè)連續(xù)帶數(shù)字圓圈效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07Android提高之模擬信號(hào)示波器的實(shí)現(xiàn)
這篇文章主要介紹了Android模擬信號(hào)示波器的實(shí)現(xiàn)方法,在Android項(xiàng)目開(kāi)發(fā)中有一定的實(shí)用價(jià)值,需要的朋友可以參考下2014-08-08Android操作Excel文件的功能實(shí)現(xiàn)
本篇文章主要介紹了Android操作Excel文件的功能實(shí)現(xiàn),Android中操作Excel文件導(dǎo)出報(bào)表時(shí)主要采用開(kāi)源庫(kù)jxl,有興趣的可以了解一下。2017-03-03android通過(guò)自定義toast實(shí)現(xiàn)懸浮通知效果的示例代碼
這篇文章主要介紹了android通過(guò)自定義toast實(shí)現(xiàn)懸浮通知效果,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-10Android實(shí)現(xiàn)網(wǎng)易新聞客戶端側(cè)滑菜單(1)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)網(wǎng)易新聞客戶端側(cè)滑菜單第一篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11flutter實(shí)現(xiàn)點(diǎn)擊事件
這篇文章主要為大家詳細(xì)介紹了flutter實(shí)現(xiàn)點(diǎn)擊事件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08Android簡(jiǎn)單實(shí)現(xiàn)引導(dǎo)頁(yè)
這篇文章主要為大家詳細(xì)介紹了Android簡(jiǎn)單實(shí)現(xiàn)引導(dǎo)頁(yè),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04