1. 程式人生 > 其它 >android 搜尋不到pad了_Android物聯網(一)—— 藍芽通訊

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)) {

}

}

}

如圖

1e8380d18349f2b92e56b8163d10ce20.png

所以主頁的全部程式碼如下:

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就會收到我們的訊息然後達成互相通訊的功能

如圖

6c963bdcb1187434362a3fd110de61b3.png

我們來看下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

有興趣的加入QQ群:555974449