最近在研究手机通过蓝牙连接另一部蓝牙设备,以达到从另一部蓝牙设备上读取数据的目的。
第一步首先自定义一个发现蓝牙设备的广播接收器。
下面是详细的代码:
package com.test;
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.os.Handler;
import android.os.Message;
public class BlueToothSearchReceiver extends BroadcastReceiver {
public static final int DEVICE_FOUND = 0;
public static final int DEVICE_NOT_FOUND = 1;
public Handler mHandler;
public BlueToothSearchReceiver(Handler handler) {
this.mHandler = handler;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action) || BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
mHandler.sendMessage(Message.obtain(mHandler, DEVICE_FOUND, device));
}
else {
mHandler.sendMessage(Message.obtain(mHandler, DEVICE_NOT_FOUND, ""));
}
}
public IntentFilter getIntentFilter() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
intentFilter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
return intentFilter;
}
}
第二步注册发现蓝牙设备的广播接收器
@Override
protected void onResume() {
super.onResume();
mBlueToothSearchReceiver = new BlueToothSearchReceiver(mHandler);
// 注册接收周边可见蓝牙设备的广播接收器
registerReceiver(mBlueToothSearchReceiver, mBlueToothSearchReceiver.getIntentFilter());
}
第三步发现蓝牙设备以后绑定到已发现的蓝牙设备列表上
第四步如果蓝牙之间已经配对,那么就进行连接操作,如果没有连接那么先进行配对操作,然后再进行连接操作,连接完成之后就等待数据读取的过程了。
下面是详细的代码:
package com.test;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class MainActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener {
private Button btnStatus, btnSearch;
private ListView lvDevices;
private EditText etMessage;
private BluetoothAdapter mBluetoothAdapter = null;
private List<BluetoothDevice> mBluetoothDeviceList = new ArrayList<>();
private MyAdapter mAdapter = null;
private BlueToothSearchReceiver mBlueToothSearchReceiver;
private static final int CONNECT_FAILURE = 2;
private static final int CONNECT_SUCCESS = 3;
private static final int WRITE_FAILED = 4;
private static final int READ_FAILED = 5;
private static final int READ_SUCCESS = 6;
private static final String KEY_SOCKET = "socket";
private static final String KEY_SOCKET_CONNECT = "connect";
private Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case BlueToothSearchReceiver.DEVICE_NOT_FOUND:
showMsg("没有发现已开启的蓝牙设备");
break;
case BlueToothSearchReceiver.DEVICE_FOUND:
BluetoothDevice device = (BluetoothDevice) msg.obj;
if (!mBluetoothDeviceList.contains(device))
mBluetoothDeviceList.add(device);
if (mAdapter != null)
mAdapter.notifyDataSetChanged();
break;
case CONNECT_FAILURE:
showMsg("连接失败");
break;
case CONNECT_SUCCESS:
showMsg("连接成功,开始读取数据");
new ThreadReadData((Map<String, Object>) msg.obj).start();
break;
case WRITE_FAILED:
showMsg("写入失败");
break;
case READ_FAILED:
showMsg("读取失败");
break;
case READ_SUCCESS:
showMsg("读取成功");
String receive = msg.obj + "";
String content = etMessage.getText().toString() + "\r\n" + receive;
etMessage.setText(content);
etMessage.setSelection(content.length());
break;
}
return false;
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
@Override
protected void onResume() {
super.onResume();
mBlueToothSearchReceiver = new BlueToothSearchReceiver(mHandler);
// 注册接收周边可见蓝牙设备的广播接收器
registerReceiver(mBlueToothSearchReceiver, mBlueToothSearchReceiver.getIntentFilter());
}
@Override
protected void onDestroy() {
if (mBluetoothAdapter != null) {
mBluetoothAdapter.cancelDiscovery();
}
super.onDestroy();
}
private void initView() {
btnStatus = (Button) findViewById(R.id.btnOpen);
btnSearch = (Button) findViewById(R.id.btnSearch);
lvDevices = (ListView) findViewById(R.id.lvDevices);
etMessage = (EditText) findViewById(R.id.etMessage);
btnStatus.setOnClickListener(this);
btnSearch.setOnClickListener(this);
lvDevices.setOnItemClickListener(this);
initBluetoothStatus();
}
private void initBluetoothStatus() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
showMsg("当前设备不存在蓝牙模块");
} else {
if (mBluetoothAdapter.isEnabled()) {
// mBluetoothAdapter.disable(); // 关闭蓝牙
btnStatus.setText("蓝牙状态:开启");
} else {
btnStatus.setText("蓝牙状态:关闭");
// 无需询问用户,直接开启蓝牙,需要android.permission.BLUETOOTH_ADMIN权限
// mBluetoothAdapter.enable();
}
}
}
private void openOrCloseBlueTooth() {
if (mBluetoothAdapter == null) {
showMsg("当前设备不存在蓝牙模块");
} else {
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable(); // 关闭蓝牙
btnStatus.setText("蓝牙状态:关闭");
} else {
// 询问用户,如果用户同意就打开蓝牙
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); // 300就表示300秒
startActivity(intent);
// 无需询问用户,直接开启蓝牙,需要android.permission.BLUETOOTH_ADMIN权限
// mBluetoothAdapter.enable();
btnStatus.setText("蓝牙状态:开启");
}
}
}
private void bindDevices() {
// 获取蓝牙适配器中已经配对的设备
if (mBluetoothAdapter != null) {
Set<BluetoothDevice> deviceList = mBluetoothAdapter.getBondedDevices();
if (deviceList != null && deviceList.size() > 0) {
for (BluetoothDevice device : deviceList) {
mBluetoothDeviceList.add(device);
}
}
}
// 显示已经绑定和可见但是还没有绑定的设备信息
mAdapter = new MyAdapter(mBluetoothDeviceList, R.layout.activity_main_item);
lvDevices.setAdapter(mAdapter);
}
private void showMsg(String msg) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnOpen:
openOrCloseBlueTooth();
break;
case R.id.btnSearch:
mBluetoothDeviceList.clear();
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
}
if (mBluetoothAdapter != null) {
mBluetoothAdapter.startDiscovery();
}
bindDevices();
break;
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mBluetoothDeviceList != null) {
final BluetoothDevice device = mBluetoothDeviceList.get(position);
int conStatus = device.getBondState();
switch (conStatus) {
case BluetoothDevice.BOND_BONDED:
/*try {
// 解除
Method removeBond = device.getClass().getMethod("removeBond", (Class<?>[]) null);
removeBond.invoke(device);
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
}
} catch (Exception e) {
e.printStackTrace();
}*/
showMsg("连接线程开始");
new ThreadBluetoothConnect(device).start();
break;
case BluetoothDevice.BOND_NONE:
try {
// 配对
Method createBond = device.getClass().getMethod("createBond", (Class<?>[]) null);
createBond.invoke(device);
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
}
/**
* 适配器
*/
class MyAdapter extends CommonAdapter<BluetoothDevice> {
public MyAdapter(List<BluetoothDevice> datas, int itemLayoutId) {
super(MainActivity.this, datas, itemLayoutId);
}
@Override
public void convert(ViewHolder holder, BluetoothDevice item) {
holder.setText(R.id.tvName, "设备名称:" + item.getName());
holder.setText(R.id.tvAddress, "设备地址:" + item.getAddress());
holder.setText(R.id.tvStatus, "匹配状态:" + getStatus(item.getBondState()));
}
private String getStatus(int status) {
switch (status) {
case BluetoothDevice.BOND_NONE:
return "未匹配";
case BluetoothDevice.BOND_BONDING:
return "匹配中";
case BluetoothDevice.BOND_BONDED:
return "已匹配";
default:
return "未匹配";
}
}
}
/**
* 蓝牙连接线程
*/
class ThreadBluetoothConnect extends Thread {
BluetoothDevice mDevice;
public ThreadBluetoothConnect(BluetoothDevice device) {
this.mDevice = device;
}
@Override
public void run() {
super.run();
/*try {
mBluetoothAdapter.cancelDiscovery();
final String spp_uuid = "00001101-0000-1000-8000-00805F9B34FB";
UUID uuid = UUID.fromString(spp_uuid);
socket = device.createRfcommSocketToServiceRecord(uuid);
socket.connect();
} catch (IOException e) {
System.err.println(e.getMessage());
}*/
mBluetoothAdapter.cancelDiscovery();
BluetoothSocket tmp = null;
Method method;
try {
method = mDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
tmp = (BluetoothSocket) method.invoke(mDevice, 1);
} catch (Exception e) {
mHandler.sendEmptyMessage(CONNECT_FAILURE);
}
try {
tmp.connect();
Map<String, Object> map = new HashMap<>();
map.put(KEY_SOCKET, tmp);
map.put(KEY_SOCKET_CONNECT, true);
mHandler.sendMessage(Message.obtain(mHandler, CONNECT_SUCCESS, map));
} catch (Exception e) {
mHandler.sendEmptyMessage(CONNECT_FAILURE);
}
}
}
class ThreadReadData extends Thread {
Map<String, Object> mData;
public ThreadReadData(Map<String, Object> data) {
this.mData = data;
}
@Override
public void run() {
super.run();
boolean connected = (boolean) mData.get(KEY_SOCKET_CONNECT);
BluetoothSocket socket = (BluetoothSocket) mData.get(KEY_SOCKET);
if (connected) {
/*try {
OutputStream outStream = socket.getOutputStream();
outStream.write(getHexBytes(""));
} catch (IOException e) {
mHandler.sendEmptyMessage(WRITE_FAILED);
}*/
try {
InputStream inputStream = socket.getInputStream();
String data;
while (true) {
try {
byte[] buffer = new byte[1024];
inputStream.read(buffer);
data = new String(buffer);
Message msg = mHandler.obtainMessage();
msg.what = READ_SUCCESS;
msg.obj = socket.getRemoteDevice().getName() + " " + data;
mHandler.sendMessage(msg);
} catch (IOException e) {
mHandler.sendEmptyMessage(READ_FAILED);
e.printStackTrace();
break;
}
}
} catch (IOException e) {
mHandler.sendEmptyMessage(WRITE_FAILED);
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/** 私有方法 */
private byte[] getHexBytes(String message) {
int len = message.length() / 2;
char[] chars = message.toCharArray();
String[] hexStr = new String[len];
byte[] bytes = new byte[len];
for (int i = 0, j = 0; j < len; i += 2, j++) {
hexStr[j] = "" + chars[i] + chars[i + 1];
bytes[j] = (byte) Integer.parseInt(hexStr[j], 16);
}
return bytes;
}
}
通过以上所提供的方法,就可以进行蓝牙通信了。
上文中用到的两个布局文件如下所示:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp">
<Button
android:id="@+id/btnOpen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="蓝牙状态"/>
<Button
android:id="@+id/btnSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/btnOpen"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="搜索设备"/>
<ListView
android:id="@+id/lvDevices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/btnSearch"
android:layout_marginTop="20dp"></ListView>
<EditText
android:id="@+id/etMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/lvDevices"
android:layout_marginTop="20dp"/>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"/>
<TextView
android:id="@+id/tvAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/tvName"
android:layout_marginTop="5dp"/>
<TextView
android:id="@+id/tvStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tvName"
android:layout_marginLeft="30dp"
android:layout_marginTop="5dp"
android:layout_toRightOf="@id/tvAddress"/>
</RelativeLayout>
该文是自己第一次写关于蓝牙方面的一些见解,如有不足之处,还请指正,谢谢!