- 通知; 2、對話框; 3、消息提示框
- 在使用Android藍(lán)牙適配器中的startDiscovery需要先打開定位服務(wù)
- 在連接藍(lán)牙之前,還要先取消藍(lán)牙設(shè)備的掃描,否則容易連接失敗
前段時間自己學(xué)做了一個基于安卓經(jīng)典藍(lán)牙的app,也遇到不少坑,在網(wǎng)上相對與BLE低功耗藍(lán)牙來說,它的資料方面都是比較缺少的,而且網(wǎng)上經(jīng)典藍(lán)牙源碼大部分都很長,對于入門的同學(xué)來說,看沒兩分鐘就產(chǎn)生放棄的念頭了。 第一步:在AndroidManifest中添加: <!--管理藍(lán)牙需要-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--搜索藍(lán)牙需要,因為藍(lán)牙可以被用來定位,所以需要定位權(quán)限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 上面都是我們使用到設(shè)備功能的權(quán)限申請。 第二步:設(shè)置兩個按鈕分別是打開和關(guān)閉藍(lán)牙 對藍(lán)牙設(shè)備干事情,那么我們就得拿到它的接口來控制它 //獲取藍(lán)牙適配器
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 打開藍(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("親,打開了噢!需要什么幫助嗎?");
}
else {
showToast("親,已經(jīng)打開了噢,無需重復(fù)打開。");
}
}
else {
showToast("親,您不支持此藍(lán)牙設(shè)備!");
}
} 2、打開藍(lán)牙應(yīng)該先確定使用的手機(jī)是否支持藍(lán)牙設(shè)備(手機(jī)沒有就沒必要進(jìn)行下一步了) //判斷是否支持藍(lán)牙
public boolean isSupportBlueTooth() {
if(mBluetoothAdapter != null) {
return true;
}
else {
return false;
}
} 3、然后打開前還需要知道手機(jī)是否打開藍(lán)牙了吧!那就獲取手機(jī)現(xiàn)在藍(lán)牙設(shè)備的狀態(tài) //獲取藍(lán)牙狀態(tài)
public boolean BlueToothState() {
assert (mBluetoothAdapter != null); //若不支持該藍(lán)牙設(shè)備會有個斷言
return mBluetoothAdapter.isEnabled();
} 2、3小步驟都只是個函數(shù)功能體,都是為1、步驟使用的,初學(xué)者會疑惑什么是斷言,就是做判斷,真的那么下面就不執(zhí)行咯!還有下面是是一個消息對象, 獲取用戶對藍(lán)牙適配器申請打開的請求消息,使用startActivityForResult對消息做出應(yīng)答,會有對話框的提示效果 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent,0); 關(guān)閉藍(lán)牙: public void CloseBlueTooth(View view) {
mBluetoothAdapter.disable();
showToast("親,我們會再見面的!");
} 先說明一點我這里的還是都在有View view形參接口,這是一個動作的監(jiān)聽接口,下圖有設(shè)置的圖片,這里設(shè)置就可以了。
感覺打開藍(lán)牙和關(guān)閉藍(lán)牙挺簡單的吧! 難度開始來了噢!
第三步: 打開了藍(lán)牙我們就得弄一個來搜索周圍的設(shè)備吧! 下面是一個定義好的搜索藍(lán)牙函數(shù) public void startDiscovery() {
if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery(); Toast.makeText(this,"搜索器打開",Toast.LENGTH_SHORT).show();}
mBluetoothAdapter.startDiscovery();
if (!mBluetoothAdapter.isDiscovering()) {Toast.makeText(this,"搜索器沒打開",Toast.LENGTH_SHORT).show();}
} 有點看不懂嗎,其實還好吧,就是第一次判斷是否開啟搜索周圍藍(lán)牙設(shè)備,開啟了就把它關(guān)了,重新打開在搜索,在判斷我是否開啟了搜索沒。(isDiscovery是開啟搜索,cancelDiscovery是關(guān)閉搜索的意思) 有搜索藍(lán)牙設(shè)備函數(shù)了,我們就搞一個按鍵讓其有觸發(fā)效果吧! //按鈕搜尋藍(lán)牙
Button button_discovery = (Button) findViewById(R.id.DiscoveryBT);
button_discovery.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startDiscovery();
}
}); 開啟了搜索藍(lán)牙設(shè)備我們得有東西接收這些設(shè)備吧,不然它偷偷摸摸搜索鬼知道它搜了什么東西。那我們就得用廣播把這些偷偷摸摸搜索到了設(shè)備把它弄出來,放進(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, "開始", 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語句就是去除已經(jīng)獲取的藍(lán)牙設(shè)備
}
// 不是重復(fù)的就添加到列表中(獲取未配對的藍(lán)牙設(shè)備)
deviceAdress.add(device); //添加地址到列表中 用于鑒別是否已經(jīng)添加列表和點擊事件用的
deviceName.add("地址:"+device.getAddress()+"\n"+"名稱:"+device.getName()); //存放藍(lán)牙名稱和地址用于顯示到列表上的
} else if(intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
}
}
} 代碼都有注釋我就不一一說明了,說一下箱子要在外面定義 public ArrayList<BluetoothDevice> deviceAdress = new ArrayList<>(); //存放藍(lán)牙設(shè)備(這里Adress我忘了改過來了,這是存放設(shè)備不是設(shè)備地址)
public ArrayList<String> deviceName = new ArrayList<>(); //存放藍(lán)牙名稱和地址 然后就是用廣播類里面用if那些進(jìn)行信息篩選(用藍(lán)牙設(shè)備這個方法獲取設(shè)備的信息BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) 然后就是把搜索到的device 你可以用Toast.make()打印一下信息看看效果 記得廣播接收器的使用一定要注冊廣播接收器,不然就廢掉了 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 );//搜索啟動
//上面是添加動作事件
//注冊廣播接收者的對象
registerReceiver(myReceiver,intentFilter); 都放在箱子里了,我們應(yīng)該把它拿出來一個一個展示一下吧! 這展示的方法就是用列表把它展示出來: public ListView listView; //定義展示列表
//////////////////////////////////////////////創(chuàng)建搜索藍(lán)牙列表的///////////////////////////////////////////////////////////////////并把
arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_expandable_list_item_1,deviceName); //實例化ArrayAdapter對象deviceName集合數(shù)據(jù)放入arrayAdapter適配器集合內(nèi)
listView = (ListView) findViewById(R.id.list); //獲取列表框的
listView.setAdapter(arrayAdapter); //將arrayAdapter集合內(nèi)的數(shù)據(jù)加載到列表框 就是適配器對象與ListView關(guān)聯(lián) 這樣放進(jìn)列表你以為就可以了嗎,你怎么知道它加載了多少個已發(fā)現(xiàn)的設(shè)備呢?這需要我們到廣播接收器這個線程中間斷刷新載入新設(shè)備 arrayAdapter.notifyDataSetChanged(); //更新列表 下面是我定義的一個刷新列表搜索 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)行點擊觸發(fā) //連接藍(lán)牙
public void Connect_BT(ArrayList<BluetoothDevice> deviceAdress) {
//MainActivity 實現(xiàn)OnItemClickListener 然后重寫方法
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); //編號
Toast.makeText(MainActivity.this, s1 + "--" + clickDevice.getName() + "--" + clickDevice.getAddress(),Toast.LENGTH_SHORT).show();
//在連接前需要先關(guān)閉搜索
}
});
} 把我們列表按鍵觸發(fā)這個類放到廣播接收器這個線程中 Connect_BT(deviceAdress); 按下列表就有這個提示框咯!開心吧
第五步: 連接我們選中的藍(lán)牙 連接這些藍(lán)牙都需要協(xié)議的,都是廠家底層工作人員定好的 //手機(jī)連接的UUID
//設(shè)備連接的UUID由廠商決定。
private final String BLUETOOTH_UUID = "00001101-0000-1000-8000-00805F9B34FB"; //藍(lán)牙通信的UUID,必須為這個,如果換成其他的UUID會無法通信
private BluetoothSocket bluetoothSocket = null; UUID我就步詳細(xì)說了,你們自行百度。BluetoothSocket套接字就是連接藍(lán)牙服務(wù)器用的。 在Connect_BT添加下面代碼即可() //在連接前需要先關(guān)閉搜索
//點擊列表,去請求服務(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();
} 這我要說明一下connect方法會阻塞線程,我們需要在下面創(chuàng)建一個子線程來運行,不然程序奔潰別找我就可以了。 到這我們就所有基本弄好了
第五步: 接收和發(fā)送數(shù)據(jù) 這里我略微講一下 // 用來收數(shù)據(jù)
InputStream inputStream = bluetoothSocket.getInputStream();
// 用來發(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ù)的話會比較麻煩一點點,需要用一個線程和while死循環(huán)繼續(xù)時刻接收(因為InputStream 也會阻塞線程的)
到這就告一段落了。 我有一個老師是這樣說過的游戲打累了就休息一下,休息的方法就是敲代碼。
在社會學(xué)到的要學(xué)會分享回報社會
(有什么好的想法和建議可以分享一下給我) 廣州大學(xué)華軟軟件學(xué)院djw
全部資料51hei下載地址(源碼): |