Android物联网(一)—— 蓝牙通讯
藍牙的基礎(chǔ)知識我就不講了,有興趣可以看下我之前寫的博客,現(xiàn)在我們要做的就是實現(xiàn)兩個藍牙之間的通訊,并且實現(xiàn)聊天功能,這里大家準備兩個手機即可。
我們先按照流程走一遍,首先是驗證一下設(shè)備是否支持藍牙,一般都是支持的
if (!BtManager.getInstance().isSupport()) {Toast.makeText(this, "當(dāng)前設(shè)備不支持藍牙", Toast.LENGTH_SHORT).show();return; }然后驗證一下是否打開了藍牙
BtManager.getInstance().open();我對藍牙的相關(guān)Api是做了一些封裝的,緊接著我獲取到他之前配對過的設(shè)備
Set<BluetoothDevice> mBondedList = BtManager.getInstance().getBondedDevices(); for (BluetoothDevice device : mBondedList) {addModel(device.getName(), device.getAddress()); }這里要注意一點的是,我們需要添加權(quán)限
<uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>ACCESS_COARSE_LOCATION是后面Android6.0新需要的權(quán)限,不然搜索設(shè)備是獲取不到的
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();}緊接著在在回調(diào)中接收結(jié)果
@Overridepublic 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();}}}}如果同意了此權(quán)限就直接搜索設(shè)備了,搜索設(shè)備我們會需要用到兩個廣播
mBtFoundReceiver = new BtFoundReceiver();IntentFilter filter = new IntentFilter();//搜索結(jié)果filter.addAction(BluetoothDevice.ACTION_FOUND);//搜索完成filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);registerReceiver(mBtFoundReceiver, filter);這樣我們就可以接收到他返回的列表了
class BtFoundReceiver extends BroadcastReceiver {@Overridepublic 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;@Overrideprotected 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() {@Overridepublic 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();//搜索結(jié)果filter.addAction(BluetoothDevice.ACTION_FOUND);//搜索完成filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);registerReceiver(mBtFoundReceiver, filter);if (!BtManager.getInstance().isSupport()) {Toast.makeText(this, "當(dāng)前設(shè)備不支持藍牙", 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();}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(mBtFoundReceiver);}class BtFoundReceiver extends BroadcastReceiver {@Overridepublic 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)) {}}}/*** 添加數(shù)據(jù)** @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();}@Overridepublic 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: lgl@szokl.com.cn* 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();}/*** 開關(guān) 無提示*/public void open() {if (!isEnabled()) {mBluetoothAdapter.enable();}}/*** 開關(guān) 有提示** @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();}}/*** 獲取遠程設(shè)備** @param address* @return*/public BluetoothDevice getRemoteDevice(String address) {return mBluetoothAdapter.getRemoteDevice(address);}/*** 獲取客戶端設(shè)備* @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;} }好了,我們重點回到如何建立連接上,我們也知道,當(dāng)我們點擊設(shè)備的時候會跳轉(zhuǎn)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拿到這兩個參數(shù)之后會做什么呢?
首先,會創(chuàng)建一個AcceptThread循環(huán)讀取遠程端發(fā)送過來的消息
private class AcceptThread extends Thread {// 服務(wù)端接口private BluetoothServerSocket serverSocket;// 獲取到客戶端的接口private BluetoothSocket socket;// 獲取到輸入流private InputStream is;public AcceptThread() {serverSocket = BtManager.getInstance().listenUsingRfcommWithServiceRecord(NAME, MY_UUID);}@Overridepublic void run() {try {// 接收其客戶端的接口socket = serverSocket.accept();// 獲取到輸入流is = socket.getInputStream();while (true) {// 創(chuàng)建一個128字節(jié)的緩沖byte[] buffer = new byte[128];// 每次讀取128字節(jié),并保存其讀取的角標int count = is.read(buffer);// 創(chuàng)建Message類,向handler發(fā)送數(shù)據(jù)Message msg = new Message();// 發(fā)送一個String的數(shù)據(jù),讓他向上轉(zhuǎn)型為obj類型msg.obj = new String(buffer, 0, count, "utf-8");// 發(fā)送數(shù)據(jù)mHandler.sendMessage(msg);}} catch (IOException e) {Log.e(MainActivity.TAG, e.toString());}}}所以我們接收到數(shù)據(jù),則是在這里獲取到的,然后我們才申請建立連接
/*** 建立連接** @param address*/private void connetSocket(String address) {if (selectDevice == null) {//通過地址獲取到該設(shè)備selectDevice = BtManager.getInstance().getRemoteDevice(address);}try {if (clientSocket == null) {// 獲取到客戶端接口clientSocket = selectDevice.createRfcommSocketToServiceRecord(MY_UUID);// 向服務(wù)端發(fā)送連接clientSocket.connect();// 獲取到輸出流,向外寫數(shù)據(jù)os = clientSocket.getOutputStream();}sendText("連接成功");} catch (IOException e) {Log.e(MainActivity.TAG, e.toString());}}建立連接以后我們就可以發(fā)送數(shù)據(jù)了
/*** 發(fā)送消息** @param text*/private void sendText(final String text) {if (!TextUtils.isEmpty(text)) {if (os != null) {// 以utf-8的格式發(fā)送出去try {os.write(text.getBytes("UTF-8"));mHandler.post(new Runnable() {@Overridepublic void run() {addLeft(text);}});Log.e(MainActivity.TAG, text);} catch (IOException e) {Toast.makeText(this, "消息發(fā)送失敗:" + e.toString(), Toast.LENGTH_SHORT).show();}} else {Toast.makeText(this, "設(shè)備未連接", 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: lgl@szokl.com.cn* 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");// 為其鏈接創(chuàng)建一個名稱private final String NAME = "Bluetooth_Socket";// 選中發(fā)送數(shù)據(jù)的藍牙設(shè)備,全局變量,否則連接在方法執(zhí)行完就結(jié)束了private BluetoothDevice selectDevice;// 獲取到選中設(shè)備的客戶端串口,全局變量,否則連接在方法執(zhí)行完就結(jié)束了private BluetoothSocket clientSocket;// 獲取到向設(shè)備寫的輸出流,全局變量,否則連接在方法執(zhí)行完就結(jié)束了private OutputStream os;// 服務(wù)端利用線程不斷接受客戶端信息private AcceptThread thread;private Handler mHandler = new Handler(new Handler.Callback() {@Overridepublic 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;}});@Overrideprotected 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() {@Overridepublic void run() {connetSocket(address);}}).start();}/*** 建立連接** @param address*/private void connetSocket(String address) {if (selectDevice == null) {//通過地址獲取到該設(shè)備selectDevice = BtManager.getInstance().getRemoteDevice(address);}try {if (clientSocket == null) {// 獲取到客戶端接口clientSocket = selectDevice.createRfcommSocketToServiceRecord(MY_UUID);// 向服務(wù)端發(fā)送連接clientSocket.connect();// 獲取到輸出流,向外寫數(shù)據(jù)os = clientSocket.getOutputStream();}sendText("連接成功");} catch (IOException e) {Log.e(MainActivity.TAG, e.toString());}}/*** 發(fā)送消息** @param text*/private void sendText(final String text) {if (!TextUtils.isEmpty(text)) {if (os != null) {// 以utf-8的格式發(fā)送出去try {os.write(text.getBytes("UTF-8"));mHandler.post(new Runnable() {@Overridepublic void run() {addLeft(text);}});Log.e(MainActivity.TAG, text);} catch (IOException e) {Toast.makeText(this, "消息發(fā)送失敗:" + e.toString(), Toast.LENGTH_SHORT).show();}} else {Toast.makeText(this, "設(shè)備未連接", Toast.LENGTH_SHORT).show();}}}@Overridepublic 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 {// 服務(wù)端接口private BluetoothServerSocket serverSocket;// 獲取到客戶端的接口private BluetoothSocket socket;// 獲取到輸入流private InputStream is;public AcceptThread() {serverSocket = BtManager.getInstance().listenUsingRfcommWithServiceRecord(NAME, MY_UUID);}@Overridepublic void run() {try {// 接收其客戶端的接口socket = serverSocket.accept();// 獲取到輸入流is = socket.getInputStream();while (true) {// 創(chuàng)建一個128字節(jié)的緩沖byte[] buffer = new byte[128];// 每次讀取128字節(jié),并保存其讀取的角標int count = is.read(buffer);// 創(chuàng)建Message類,向handler發(fā)送數(shù)據(jù)Message msg = new Message();// 發(fā)送一個String的數(shù)據(jù),讓他向上轉(zhuǎn)型為obj類型msg.obj = new String(buffer, 0, count, "utf-8");// 發(fā)送數(shù)據(jù)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();} }這個只是一個簡單的實現(xiàn)Demo,有興趣的自己去鉆研一下
點擊下載
有興趣的加入群:555974449
總結(jié)
以上是生活随笔為你收集整理的Android物联网(一)—— 蓝牙通讯的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用牛顿法求算术平方根python
- 下一篇: Jmeter Ant Jenkins报告