一、藍(lán)牙搜索功能的實(shí)現(xiàn)
1.權(quán)限
AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
如果SDK_INT>=23需要?jiǎng)討B(tài)申請權(quán)限
if(Build.VERSION.SDK_INT>=23){
//判斷是否有權(quán)限
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION)!= PackageManager.PERMISSION_GRANTED) {
//請求權(quán)限
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.BLUETOOTH,Manifest.permission.BLUETOOTH_ADMIN},
100);
//向用戶解釋吊说,為什么要申請?jiān)摍?quán)限
if(ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_CONTACTS)) {
Toast.makeText(MainActivity.this,"shouldShowRequestPermissionRationale", Toast.LENGTH_SHORT).show();
}
}
}
2.基本使用
得到藍(lán)牙適配器:
BluetoothAdapter mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
若mBluetoothAdapter為 null省核,則說明當(dāng)前手機(jī)不支持藍(lán)牙功能
打開藍(lán)牙:
//若沒打開則打開藍(lán)牙
mBluetoothAdapter.enable();
判斷藍(lán)牙是否打開:
mBluetoothAdapter.isEnabled()
關(guān)閉藍(lán)牙:
mBluetoothAdapter.disable();
開始搜索:
mBluetoothAdapter.startDiscovery();
取消搜索:
mBluetoothAdapter.cancelDiscovery();
判斷是否在搜索中:
mBluetoothAdapter.isDiscovering();
開始廣播會(huì)觸發(fā)廣播接收器中的onReceiver()方法榄审。
判斷是否打開藍(lán)牙
//1.判斷是否打開藍(lán)牙
if (!mBluetoothAdapter.isEnabled()) {
//若沒打開則打開藍(lán)牙
mBluetoothAdapter.enable();
Toast.makeText(MainActivity.this,"藍(lán)牙已打開",Toast.LENGTH_SHORT).show();
tvName.setText("藍(lán)牙已打開");
}
//2.判斷是否打開藍(lán)牙
mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter== null) {
Toast.makeText(this,"設(shè)備上沒有發(fā)現(xiàn)有藍(lán)牙設(shè)備",Toast.LENGTH_SHORT).show();
}else {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
}
}
3.廣播
動(dòng)態(tài)注冊廣播
IntentFilter iFilter = new IntentFilter(
BluetoothAdapter.ACTION_DISCOVERY_STARTED);
registerReceiver(mSearchReceiver, iFilter);
// 創(chuàng)建一個(gè)查找藍(lán)牙設(shè)備的廣播意圖
iFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
// 注冊一個(gè)廣播接收者巾遭,開啟查找藍(lán)牙設(shè)備意圖后將結(jié)果以廣播的形式返回
registerReceiver(mSearchReceiver, iFilter);
// 創(chuàng)建一個(gè)結(jié)束查找藍(lán)牙設(shè)備結(jié)束的廣播意圖
iFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mSearchReceiver, iFilter);
具體代碼:
//開始搜索
public void startBlue(){
//正在搜索就先取消搜索
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
mBluetoothAdapter.startDiscovery();
IntentFilter iFilter = new IntentFilter(
BluetoothAdapter.ACTION_DISCOVERY_STARTED);
registerReceiver(mSearchReceiver, iFilter);
// 創(chuàng)建一個(gè)查找藍(lán)牙設(shè)備的廣播意圖
iFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
// 注冊一個(gè)廣播接收者若河,開啟查找藍(lán)牙設(shè)備意圖后將結(jié)果以廣播的形式返回
registerReceiver(mSearchReceiver, iFilter);
// 創(chuàng)建一個(gè)結(jié)束查找藍(lán)牙設(shè)備結(jié)束的廣播意圖
iFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mSearchReceiver, iFilter);
}
創(chuàng)建廣播:
private BroadcastReceiver mSearchReceiver = new BroadcastReceiver() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
//搜索前
data.clear();
break;
case BluetoothDevice.ACTION_FOUND:
//搜索中
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
for (int i = 0; i < data.size(); i++) {
if(data.get(i).equals(device.getName())) {
return;
}
}
data.add(device.getName());
Log.e("tag","name======"+device.getName());
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
//搜索完成
// 設(shè)置adapter
if(data.size()>0) {
mAdapter = new MyAdapter(data);
my_recycler_view.setAdapter(mAdapter);
}else {
Toast.makeText(SearchListActivity.this,"設(shè)備上沒有發(fā)現(xiàn)有藍(lán)牙設(shè)備",Toast.LENGTH_SHORT).show();
}
break;
}
}
};
解除注冊:
@Override
protected void onDestroy() {
super.onDestroy();
//解除注冊
unregisterReceiver(mSearchReceiver);
}
二幅狮、手機(jī)端藍(lán)牙模塊通信
1.創(chuàng)建連接
//創(chuàng)建連接
new ConnectTask().execute(address);
連接藍(lán)牙設(shè)備的異步任務(wù)
class ConnectTask extends AsyncTask<String,String,String>
{
@Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(params[0]);
try {
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
btSocket.connect();
Log.e("error", "ON RESUME: BT connection established, data transfer link open.");
} catch (IOException e) {
try {
btSocket.close();
return "Socket 創(chuàng)建失敗";
} catch (IOException e2) {
Log .e("error","ON RESUME: Unable to close socket during connection failure", e2);
return "Socket 關(guān)閉失敗";
}
}
//取消搜索
mBluetoothAdapter.cancelDiscovery();
try {
outStream = btSocket.getOutputStream();
} catch (IOException e) {
Log.e("error", "ON RESUME: Output stream creation failed.", e);
return "Socket 流創(chuàng)建失敗";
}
return "藍(lán)牙連接正常,Socket 創(chuàng)建成功";
}
@Override //這個(gè)方法是在主線程中運(yùn)行的募强,所以可以更新界面
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
//連接成功則啟動(dòng)監(jiān)聽
rThread=new ReceiveThread();
rThread.start();
statusLabel.setText(result);
super.onPostExecute(result);
}
}
從藍(lán)牙接收信息的線程
class ReceiveThread extends Thread
{
String buffer="";
@Override
public void run() {
while(btSocket!=null )
{
//定義一個(gè)存儲(chǔ)空間buff
byte[] buff=new byte[1024];
try {
inStream = btSocket.getInputStream();
System.out.println("waitting for instream");
if(null!=inStream) {
inStream.read(buff); //讀取數(shù)據(jù)存儲(chǔ)在buff數(shù)組中
processBuffer(buff,1024);
}
// System.out.println("buff receive :"+buff.length);
//System.out.println("receive content:"+ReceiveData);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void processBuffer(byte[] buff,int size)
{
int length=0;
for(int i=0;i<size;i++)
{
if(buff[i]>'\0')
{
length++;
}
else
{
break;
}
}
// System.out.println("receive fragment size:"+length);
byte[] newbuff=new byte[length]; //newbuff字節(jié)數(shù)組,用于存放真正接收到的數(shù)據(jù)
for(int j=0;j<length;j++)
{
newbuff[j]=buff[j];
}
ReceiveData=ReceiveData+new String(newbuff);
Log.e("Data",ReceiveData);
// System.out.println("result :"+ReceiveData);
Message msg= Message.obtain();
msg.what=1;
handler.sendMessage(msg); //發(fā)送消息:系統(tǒng)會(huì)自動(dòng)調(diào)用handleMessage( )方法來處理消息
}
}
發(fā)送數(shù)據(jù)的異步任務(wù)
new SendInfoTask().execute(etSend.getText().toString());
//發(fā)送數(shù)據(jù)到藍(lán)牙設(shè)備的異步任務(wù)
class SendInfoTask extends AsyncTask<String,String,String>
{
@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
statusLabel.setText(result);
//將發(fā)送框清空
etSend.setText("");
}
@Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
if(btSocket==null)
{
return "還沒有創(chuàng)建連接";
}
if(arg0[0].length()>0)//不是空白串
{
//String target=arg0[0];
byte[] msgBuffer = arg0[0].getBytes();
try {
// 將msgBuffer中的數(shù)據(jù)寫到outStream對象中
outStream.write(msgBuffer);
} catch (IOException e) {
Log.e("error", "ON RESUME: Exception during write.", e);
return "發(fā)送失敗";
}
}
return "發(fā)送成功";
}
}