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)文章
Android編程實(shí)現(xiàn)小說(shuō)閱讀器滑動(dòng)效果的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)小說(shuō)閱讀器滑動(dòng)效果的方法,涉及onTouch事件滑動(dòng)效果的相關(guān)實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
新版Flutter集成到已有Android項(xiàng)目的實(shí)現(xiàn)
這篇文章主要介紹了新版Flutter集成到已有Android項(xiàng)目的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Android開(kāi)發(fā)實(shí)現(xiàn)讀取assets目錄下db文件的方法示例
這篇文章主要介紹了Android開(kāi)發(fā)實(shí)現(xiàn)讀取assets目錄下db文件的方法,結(jié)合實(shí)例形式分析了Android針對(duì)assets目錄下SQLite數(shù)據(jù)庫(kù)文件的相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
Android編程實(shí)現(xiàn)滑動(dòng)按鈕功能詳解
這篇文章主要介紹了Android編程實(shí)現(xiàn)滑動(dòng)按鈕功能,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android實(shí)現(xiàn)滑動(dòng)按鈕的功能、布局及相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-02-02
Android Studio EditText點(diǎn)擊圖標(biāo)清除文本內(nèi)容的實(shí)例解析
這篇文章主要介紹了Android Studio EditText點(diǎn)擊圖標(biāo)清除文本內(nèi)容的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11
分享一個(gè)Android設(shè)置圓形圖片的特別方法
圓形圖片想必是項(xiàng)目開(kāi)發(fā)中也是不少用的一個(gè)知識(shí)點(diǎn)吧。那么這里學(xué)習(xí)一下簡(jiǎn)單的制作圓形圖片,這個(gè)方法不用于平時(shí)的實(shí)現(xiàn)方法,有需要的可以參考借鑒。2016-09-09
Android 控制wifi 相關(guān)操作實(shí)例
本篇文章主要介紹了Android 控制wifi 的開(kāi)發(fā)實(shí)例,并附有實(shí)例源碼等相關(guān)資料,需要的朋友可以參考下2016-07-07
Android實(shí)現(xiàn)仿iOS菊花加載圈動(dòng)畫效果
iOS上有一個(gè)UIActivityIndicator的控件,就是俗稱轉(zhuǎn)菊花的控件,一般UI設(shè)計(jì)師會(huì)按照iOS的風(fēng)格來(lái)出設(shè)計(jì)稿,也要求使用這種Loading效果,本文將具體的講述如何實(shí)現(xiàn)這種效果,感興趣的朋友可以參考下2021-05-05

