android 搜尋不到pad了_Android物聯網(一)—— 藍芽通訊
技術標籤:android 搜尋不到pad了
藍芽的基礎知識我就不講了,有興趣可以看下我之前寫的部落格,現在我們要做的就是實現兩個藍芽之間的通訊,並且實現聊天功能,這裡大家準備兩個手機即可。
我們先按照流程走一遍,首先是驗證一下裝置是否支援藍芽,一般都是支援的
if (!BtManager.getInstance().isSupport()) {
Toast.makeText(this, "當前裝置不支援藍芽", Toast.LENGTH_SHORT).show();
return;
}
然後驗證一下是否打開了藍芽
BtManager.getInstance().open();
我對藍芽的相關Api是做了一些封裝的,緊接著我獲取到他之前配對過的裝置
Set<BluetoothDevice> mBondedList = BtManager.getInstance().getBondedDevices();
for (BluetoothDevice device : mBondedList) {
addModel(device.getName(), device.getAddress());
}
這裡要注意一點的是,我們需要新增許可權
android:name="android.permission.BLUETOOTH" />
android:name="android.permission.BLUETOOTH_ADMIN" />
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
ACCESSCOARSELOCATION是後面Android6.0新需要的許可權,不然搜尋裝置是獲取不到的
private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
} else {
startDiscovery();
}
} else {
startDiscovery();
}
}
private void startDiscovery() {
BtManager.getInstance().startDiscovery();
}
緊接著在在回撥中接收結果
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
for (int i = 0; i < permissions.length; i++) {
if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
int result = grantResults[i];
if (result == PackageManager.PERMISSION_GRANTED) {
startDiscovery();
} else {
requestPermission();
}
}
}
}
如果同意了此許可權就直接搜尋裝置了,搜尋裝置我們會需要用到兩個廣播
mBtFoundReceiver = new BtFoundReceiver();
IntentFilter filter = new IntentFilter();
//搜尋結果
filter.addAction(BluetoothDevice.ACTION_FOUND);
//搜尋完成
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mBtFoundReceiver, filter);
這樣我們就可以接收到他返回的列表了
class BtFoundReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device != null) {
//判斷是否配對過
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
addModel(device.getName(), device.getAddress());
}
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
}
}
}
如圖
所以主頁的全部程式碼如下:
package com.liuguilin.iot_bt;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.Window;
import android.widget.Toast;
import com.liuguilin.iot_bt.adapter.BtListAdapter;
import com.liuguilin.iot_bt.manager.BtManager;
import com.liuguilin.iot_bt.model.BtListModel;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* IOT系列部落格 —— BT 通訊
* 作者:劉桂林
*/
public class MainActivity extends AppCompatActivity {
public static final String TAG = "IOT_BT";
public static final int PERMISSION_REQUEST_COARSE_LOCATION = 1001;
private RecyclerView mBtListRyView;
private BtListAdapter mBtListAdapter;
private List<BtListModel> mList = new ArrayList<>();
private BtFoundReceiver mBtFoundReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mBtListRyView = (RecyclerView) findViewById(R.id.mBtListRyView);
mBtListRyView.setLayoutManager(new LinearLayoutManager(this));
mBtListAdapter = new BtListAdapter(this, mList);
mBtListRyView.setAdapter(mBtListAdapter);
mBtListAdapter.setOnItemClickListener(new BtListAdapter.OnItemClickListener() {
@Override
public void OnClick(int i) {
BtManager.getInstance().cancelDiscovery();
Intent intent = new Intent(MainActivity.this, ChatActivity.class);
BtListModel model = mList.get(i);
intent.putExtra("name", model.getName());
intent.putExtra("address", model.getAddress());
startActivity(intent);
}
});
mBtFoundReceiver = new BtFoundReceiver();
IntentFilter filter = new IntentFilter();
//搜尋結果
filter.addAction(BluetoothDevice.ACTION_FOUND);
//搜尋完成
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mBtFoundReceiver, filter);
if (!BtManager.getInstance().isSupport()) {
Toast.makeText(this, "當前裝置不支援藍芽", Toast.LENGTH_SHORT).show();
return;
}
BtManager.getInstance().open();
Set<BluetoothDevice> mBondedList = BtManager.getInstance().getBondedDevices();
for (BluetoothDevice device : mBondedList) {
addModel(device.getName(), device.getAddress());
}
requestPermission();
}
private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
} else {
startDiscovery();
}
} else {
startDiscovery();
}
}
private void startDiscovery() {
BtManager.getInstance().startDiscovery();
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mBtFoundReceiver);
}
class BtFoundReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device != null) {
//判斷是否配對過
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
addModel(device.getName(), device.getAddress());
}
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
}
}
}
/**
* 新增資料
*
* @param name
* @param address
*/
private void addModel(String name, String address) {
Log.e(TAG, "name:" + name + "address:" + address);
if (TextUtils.isEmpty(name)) {
return;
}
if (TextUtils.isEmpty(address)) {
return;
}
boolean isAdd = false;
for (int i = 0; i < mList.size(); i++) {
if (mList.get(i).getAddress().equals(address)) {
isAdd = true;
}
}
if (isAdd) {
return;
}
BtListModel model = new BtListModel();
model.setName(name);
model.setAddress(address);
mList.add(model);
mBtListAdapter.notifyDataSetChanged();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
for (int i = 0; i < permissions.length; i++) {
if (permissions[i].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
int result = grantResults[i];
if (result == PackageManager.PERMISSION_GRANTED) {
startDiscovery();
} else {
requestPermission();
}
}
}
}
}
再來看下封裝的藍芽管理類
package com.liuguilin.iot_bt.manager;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.content.Intent;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
/**
* FileName: BtManager
* Founder: LiuGuiLin
* Create Date: 2019/2/12 11:39
* Email: [email protected]
* Profile: 藍芽控制管理類
*/
public class BtManager {
private static BtManager mInstance = null;
private BluetoothAdapter mBluetoothAdapter;
private BtManager() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
public static BtManager getInstance() {
if (mInstance == null) {
synchronized (BtManager.class) {
if (mInstance == null) {
mInstance = new BtManager();
}
}
}
return mInstance;
}
/**
* 是否支援
*
* @return
*/
public boolean isSupport() {
return mBluetoothAdapter != null;
}
/**
* 是否開啟
*
* @return
*/
public boolean isEnabled() {
return mBluetoothAdapter.isEnabled();
}
/**
* 開關 無提示
*/
public void open() {
if (!isEnabled()) {
mBluetoothAdapter.enable();
}
}
/**
* 開關 有提示
*
* @param mActivity
* @param requestCode
*/
public void open(Activity mActivity, int requestCode) {
if (!isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
mActivity.startActivityForResult(intent, requestCode);
}
}
/**
* 獲取已配對列表
*
* @return
*/
public Set<BluetoothDevice> getBondedDevices() {
return mBluetoothAdapter.getBondedDevices();
}
/**
* 是否在搜尋
*
* @return
*/
public boolean isDiscovering() {
return mBluetoothAdapter.isDiscovering();
}
/**
* 開始搜尋
*/
public void startDiscovery() {
if (!isDiscovering()) {
mBluetoothAdapter.startDiscovery();
}
}
/**
* 停止搜尋
*/
public void cancelDiscovery() {
if (isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
}
/**
* 獲取遠端裝置
*
* @param address
* @return
*/
public BluetoothDevice getRemoteDevice(String address) {
return mBluetoothAdapter.getRemoteDevice(address);
}
/**
* 獲取客戶端裝置
* @param name
* @param uuid
* @return
*/
public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) {
try {
return mBluetoothAdapter.listenUsingRfcommWithServiceRecord(name, uuid);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
好了,我們重點回到如何建立連線上,我們也知道,當我們點選裝置的時候會跳轉ChatActivity
Intent intent = new Intent(MainActivity.this, ChatActivity.class);
BtListModel model = mList.get(i);
intent.putExtra("name", model.getName());
intent.putExtra("address", model.getAddress());
startActivity(intent);
那ChatActivity拿到這兩個引數之後會做什麼呢?
首先,會建立一個AcceptThread迴圈讀取遠端端傳送過來的訊息
private class AcceptThread extends Thread {
// 服務端介面
private BluetoothServerSocket serverSocket;
// 獲取到客戶端的介面
private BluetoothSocket socket;
// 獲取到輸入流
private InputStream is;
public AcceptThread() {
serverSocket = BtManager.getInstance().listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
}
@Override
public void run() {
try {
// 接收其客戶端的介面
socket = serverSocket.accept();
// 獲取到輸入流
is = socket.getInputStream();
while (true) {
// 建立一個128位元組的緩衝
byte[] buffer = new byte[128];
// 每次讀取128位元組,並儲存其讀取的角標
int count = is.read(buffer);
// 建立Message類,向handler傳送資料
Message msg = new Message();
// 傳送一個String的資料,讓他向上轉型為obj型別
msg.obj = new String(buffer, 0, count, "utf-8");
// 傳送資料
mHandler.sendMessage(msg);
}
} catch (IOException e) {
Log.e(MainActivity.TAG, e.toString());
}
}
}
所以我們接收到資料,則是在這裡獲取到的,然後我們才申請建立連線
/**
* 建立連線
*
* @param address
*/
private void connetSocket(String address) {
if (selectDevice == null) {
//通過地址獲取到該裝置
selectDevice = BtManager.getInstance().getRemoteDevice(address);
}
try {
if (clientSocket == null) {
// 獲取到客戶端介面
clientSocket = selectDevice.createRfcommSocketToServiceRecord(MY_UUID);
// 向服務端傳送連線
clientSocket.connect();
// 獲取到輸出流,向外寫資料
os = clientSocket.getOutputStream();
}
sendText("連線成功");
} catch (IOException e) {
Log.e(MainActivity.TAG, e.toString());
}
}
建立連線以後我們就可以傳送資料了
/**
* 傳送訊息
*
* @param text
*/
private void sendText(final String text) {
if (!TextUtils.isEmpty(text)) {
if (os != null) {
// 以utf-8的格式傳送出去
try {
os.write(text.getBytes("UTF-8"));
mHandler.post(new Runnable() {
@Override
public void run() {
addLeft(text);
}
});
Log.e(MainActivity.TAG, text);
} catch (IOException e) {
Toast.makeText(this, "訊息傳送失敗:" + e.toString(), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "裝置未連線", Toast.LENGTH_SHORT).show();
}
}
}
與此同時,對方的AcceptThread就會收到我們的訊息然後達成互相通訊的功能
如圖
我們來看下ChatActivity的所有程式碼
package com.liuguilin.iot_bt;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.liuguilin.iot_bt.adapter.ChatListAdapter;
import com.liuguilin.iot_bt.manager.BtManager;
import com.liuguilin.iot_bt.model.ChatListModel;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* FileName: ChatActivity
* Founder: LiuGuiLin
* Create Date: 2019/2/12 15:52
* Email: [email protected]
* Profile:聊天
*/
public class ChatActivity extends AppCompatActivity implements View.OnClickListener {
private RecyclerView mChatRyView;
private EditText et_text;
private Button btn_send;
private ChatListAdapter mChatListAdapter;
private List<ChatListModel> mList = new ArrayList<>();
// UUID,藍芽建立連結需要的
private final UUID MY_UUID = UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");
// 為其連結建立一個名稱
private final String NAME = "Bluetooth_Socket";
// 選中傳送資料的藍芽裝置,全域性變數,否則連線在方法執行完就結束了
private BluetoothDevice selectDevice;
// 獲取到選中裝置的客戶端串列埠,全域性變數,否則連線在方法執行完就結束了
private BluetoothSocket clientSocket;
// 獲取到向裝置寫的輸出流,全域性變數,否則連線在方法執行完就結束了
private OutputStream os;
// 服務端利用執行緒不斷接受客戶端資訊
private AcceptThread thread;
private Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
String text = (String) msg.obj;
Log.e(MainActivity.TAG, "text:" + text);
addRight(text);
Toast.makeText(ChatActivity.this, text, Toast.LENGTH_SHORT).show();
return false;
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
initView();
}
private void initView() {
mChatRyView = (RecyclerView) findViewById(R.id.mChatRyView);
et_text = (EditText) findViewById(R.id.et_text);
btn_send = (Button) findViewById(R.id.btn_send);
btn_send.setOnClickListener(this);
mChatRyView.setLayoutManager(new LinearLayoutManager(this));
mChatListAdapter = new ChatListAdapter(this, mList);
mChatRyView.setAdapter(mChatListAdapter);
Intent intent = getIntent();
String name = intent.getStringExtra("name");
final String address = intent.getStringExtra("address");
getSupportActionBar().setTitle(name);
thread = new AcceptThread();
thread.start();
new Thread(new Runnable() {
@Override
public void run() {
connetSocket(address);
}
}).start();
}
/**
* 建立連線
*
* @param address
*/
private void connetSocket(String address) {
if (selectDevice == null) {
//通過地址獲取到該裝置
selectDevice = BtManager.getInstance().getRemoteDevice(address);
}
try {
if (clientSocket == null) {
// 獲取到客戶端介面
clientSocket = selectDevice.createRfcommSocketToServiceRecord(MY_UUID);
// 向服務端傳送連線
clientSocket.connect();
// 獲取到輸出流,向外寫資料
os = clientSocket.getOutputStream();
}
sendText("連線成功");
} catch (IOException e) {
Log.e(MainActivity.TAG, e.toString());
}
}
/**
* 傳送訊息
*
* @param text
*/
private void sendText(final String text) {
if (!TextUtils.isEmpty(text)) {
if (os != null) {
// 以utf-8的格式傳送出去
try {
os.write(text.getBytes("UTF-8"));
mHandler.post(new Runnable() {
@Override
public void run() {
addLeft(text);
}
});
Log.e(MainActivity.TAG, text);
} catch (IOException e) {
Toast.makeText(this, "訊息傳送失敗:" + e.toString(), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "裝置未連線", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_send:
String text = et_text.getText().toString().trim();
sendText(text);
et_text.setText("");
break;
}
}
private class AcceptThread extends Thread {
// 服務端介面
private BluetoothServerSocket serverSocket;
// 獲取到客戶端的介面
private BluetoothSocket socket;
// 獲取到輸入流
private InputStream is;
public AcceptThread() {
serverSocket = BtManager.getInstance().listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
}
@Override
public void run() {
try {
// 接收其客戶端的介面
socket = serverSocket.accept();
// 獲取到輸入流
is = socket.getInputStream();
while (true) {
// 建立一個128位元組的緩衝
byte[] buffer = new byte[128];
// 每次讀取128位元組,並儲存其讀取的角標
int count = is.read(buffer);
// 建立Message類,向handler傳送資料
Message msg = new Message();
// 傳送一個String的資料,讓他向上轉型為obj型別
msg.obj = new String(buffer, 0, count, "utf-8");
// 傳送資料
mHandler.sendMessage(msg);
}
} catch (IOException e) {
Log.e(MainActivity.TAG, e.toString());
}
}
}
private void addLeft(String text) {
ChatListModel model = new ChatListModel();
model.setType(ChatListAdapter.LEFT_TEXT);
model.setLeftText(text);
mList.add(model);
mChatListAdapter.notifyDataSetChanged();
}
private void addRight(String text) {
ChatListModel model = new ChatListModel();
model.setType(ChatListAdapter.RIGHT_TEXT);
model.setRightText(text);
mList.add(model);
mChatListAdapter.notifyDataSetChanged();
}
}
這個只是一個簡單的實現Demo,有興趣的自己去鑽研一下
點選下載:
https://download.csdn.net/download/qq_26787115/10964151