?解释都在代码里。可以通过复制到IDEL中,然后慢慢分析,很全面,直接用就可以
一? AndroidManifest.xml中添加权限
<!-- 蓝牙 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 仅在支持BLE(即蓝牙4.0)的设备上运行 -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<!-- 如果Android6.0 蓝牙搜索不到设备,需要补充下面两个权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
二 新建一个bean文件夹然后新建类BlueDevice?
public class BlueDevice {
public String name; // 蓝牙设备的名称
public String address; // 蓝牙设备的MAC地址
public int state; // 蓝牙设备的绑定状态
public BlueDevice(String name, String address, int state) {
this.name = name;
this.address = address;
this.state = state;
}
}
这里定义了三个基本的设置参数
三 新建一个adapter文件夹后新建类BlueListAdapter
展示蓝牙设备列表的适配器
// 展示蓝牙设备列表的适配器
public class BlueListAdapter extends BaseAdapter {
private static final String TAG = "BlueListAdapter";
private Context mContext;
private ArrayList<BlueDevice> mBlueList = new ArrayList<BlueDevice>();
private String[] mStateArray = {"未绑定", "绑定中", "已绑定", "已连接"};
public static int CONNECTED = 13;
public BlueListAdapter(Context context, ArrayList<BlueDevice> blue_list) {
mContext = context;
mBlueList = blue_list;
}
@Override
public int getCount() {
return mBlueList.size();
}
@Override
public Object getItem(int position) {
return mBlueList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_bluetooth, null);
holder.tv_blue_name = convertView.findViewById(R.id.tv_blue_name);
holder.tv_blue_address = convertView.findViewById(R.id.tv_blue_address);
holder.tv_blue_state = convertView.findViewById(R.id.tv_blue_state);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
BlueDevice device = mBlueList.get(position);
holder.tv_blue_name.setText(device.name); // 显示蓝牙设备的名称
holder.tv_blue_address.setText(device.address); // 显示蓝牙设备的地址
holder.tv_blue_state.setText(mStateArray[device.state-10]); // 显示蓝牙设备的状态
return convertView;
}
public final class ViewHolder {
public TextView tv_blue_name;
public TextView tv_blue_address;
public TextView tv_blue_state;
}
}
四 新建一个util类后新建一个BluetoothUtil
里面封装了打开以及关闭蓝牙和获取蓝牙状态的各种方法
public class BluetoothUtil {
private final static String TAG = "BluetoothUtil";
// 获取蓝牙的开关状态
public static boolean getBlueToothStatus(Context context) {
//getDefaultAdapter静态方法,获取默认的蓝牙适配器BluetoothAdapter
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//enabled启用蓝牙功能
boolean enabled;
//getState获取蓝牙开关状态
switch (bluetoothAdapter.getState()) {
//STATE_ON已开启
case BluetoothAdapter.STATE_ON:
//STATE_TURNING_ON正在开启
case BluetoothAdapter.STATE_TURNING_ON:
enabled = true;
break;
case BluetoothAdapter.STATE_OFF:
case BluetoothAdapter.STATE_TURNING_OFF:
default:
enabled = false;
break;
}
return enabled;
}
// 打开或关闭蓝牙
public static void setBlueToothStatus(Context context, boolean enabled) {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (enabled) {
bluetoothAdapter.enable();
} else {
//disable禁用蓝牙
bluetoothAdapter.disable();
}
}
// 建立蓝牙配对
public static boolean createBond(BluetoothDevice device) {
try {
Method createBondMethod = BluetoothDevice.class.getMethod("createBond");
Log.d(TAG, "开始配对");
Boolean result = (Boolean) createBondMethod.invoke(device);
Log.d(TAG, "配对结果="+result);
return result;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// 取消蓝牙配对
public static boolean removeBond(BluetoothDevice device) {
try {
Method createBondMethod = BluetoothDevice.class.getMethod("removeBond");
Log.d(TAG, "取消配对");
Boolean result = (Boolean) createBondMethod.invoke(device);
Log.d(TAG, "取消结果="+result);
return result;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// 建立A2DP连接
public static boolean connectA2dp(BluetoothA2dp a2dp, BluetoothDevice device) {
try {
Method setMethod = BluetoothA2dp.class.getMethod("setPriority", BluetoothDevice.class, int.class);
Boolean setResult = (Boolean) setMethod.invoke(a2dp, device, 100);
Log.d(TAG, "设置优先级结果="+setResult);
Method connectMethod = BluetoothA2dp.class.getMethod("connect", BluetoothDevice.class);
Boolean connectResult = (Boolean) connectMethod.invoke(a2dp, device);
Log.d(TAG, "A2DP连接结果="+connectResult);
return connectResult;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// 取消A2DP连接
public static boolean disconnectA2dp(BluetoothA2dp a2dp, BluetoothDevice device) {
try {
Method method = BluetoothA2dp.class.getMethod("disconnect", BluetoothDevice.class);
Boolean result = (Boolean) method.invoke(a2dp, device);
Log.d(TAG, "A2DP取消结果="+result);
return result;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
五 最后是主activity
@SuppressLint("SetTextI18n")
public class BluetoothActivity extends AppCompatActivity implements
OnCheckedChangeListener, OnItemClickListener {
private static final String TAG = "BluetoothActivity";
private CheckBox ck_bluetooth;
private TextView tv_discovery;
private ListView lv_bluetooth; // 声明一个用于展示蓝牙设备的列表视图对象
private BluetoothAdapter mBluetooth; // 声明一个蓝牙适配器对象
private BlueListAdapter mListAdapter; // 声明一个蓝牙设备的列表适配器对象
private ArrayList<BlueDevice> mDeviceList = new ArrayList<BlueDevice>(); // 蓝牙设备队列
private Handler mHandler = new Handler(); // 声明一个处理器对象
private int mOpenCode = 1; // 是否允许扫描蓝牙设备的选择对话框返回结果代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth);
initBluetooth(); // 初始化蓝牙适配器
ck_bluetooth = findViewById(R.id.ck_bluetooth);
tv_discovery = findViewById(R.id.tv_discovery);
lv_bluetooth = findViewById(R.id.lv_bluetooth);
ck_bluetooth.setOnCheckedChangeListener(this);
if (BluetoothUtil.getBlueToothStatus(this)) {
ck_bluetooth.setChecked(true);
}
initBlueDevice(); // 初始化蓝牙设备列表
}
// 初始化蓝牙适配器
private void initBluetooth() {
// Android从4.3开始增加支持BLE技术(即蓝牙4.0及以上版本)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
// 从系统服务中获取蓝牙管理器
BluetoothManager bm = (BluetoothManager)
getSystemService(Context.BLUETOOTH_SERVICE);
mBluetooth = bm.getAdapter();
} else {
// 获取系统默认的蓝牙适配器
mBluetooth = BluetoothAdapter.getDefaultAdapter();
}
if (mBluetooth == null) {
Toast.makeText(this, "本机未找到蓝牙功能", Toast.LENGTH_SHORT).show();
finish();
}
}
// 初始化蓝牙设备列表
private void initBlueDevice() {
mDeviceList.clear();
// 获取已经配对的蓝牙设备集合
Set<BluetoothDevice> bondedDevices = mBluetooth.getBondedDevices();
for (BluetoothDevice device : bondedDevices) {
mDeviceList.add(new BlueDevice(device.getName(), device.getAddress(), device.getBondState()));
}
if (mListAdapter == null) { // 首次打开页面,则创建一个新的蓝牙设备列表
mListAdapter = new BlueListAdapter(this, mDeviceList);
lv_bluetooth.setAdapter(mListAdapter);
lv_bluetooth.setOnItemClickListener(this);
} else { // 不是首次打开页面,则刷新蓝牙设备列表
mListAdapter.notifyDataSetChanged();
}
}
private Runnable mDiscoverable = new Runnable() {
@Override
public void run() {
// Android8.0要在已打开蓝牙功能时才会弹出下面的选择窗
if (BluetoothUtil.getBlueToothStatus(BluetoothActivity.this)) {
// 弹出是否允许扫描蓝牙设备的选择对话框
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(intent, mOpenCode);
} else {
mHandler.postDelayed(this, 1000);
}
}
};
//isChecked判断蓝牙功能是否启用
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.getId() == R.id.ck_bluetooth) {
if (isChecked) { // 开启蓝牙功能
ck_bluetooth.setText("蓝牙开");
if (!BluetoothUtil.getBlueToothStatus(this)) {
BluetoothUtil.setBlueToothStatus(this, true); // 开启蓝牙功能
}
mHandler.post(mDiscoverable);
} else { // 关闭蓝牙功能
ck_bluetooth.setText("蓝牙关");
cancelDiscovery(); // 取消蓝牙设备的搜索
BluetoothUtil.setBlueToothStatus(this, false); // 关闭蓝牙功能
initBlueDevice(); // 初始化蓝牙设备列表
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == mOpenCode) { // 来自允许蓝牙扫描的对话框
// 延迟50毫秒后启动蓝牙设备的刷新任务
mHandler.postDelayed(mRefresh, 50);
if (resultCode == RESULT_OK) {
Toast.makeText(this, "允许本地蓝牙被附近的其它蓝牙设备发现",
Toast.LENGTH_SHORT).show();
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "不允许蓝牙被附近的其它蓝牙设备发现",
Toast.LENGTH_SHORT).show();
}
}
}
// 定义一个刷新任务,每隔两秒刷新扫描到的蓝牙设备
private Runnable mRefresh = new Runnable() {
@Override
public void run() {
beginDiscovery(); // 开始扫描周围的蓝牙设备
// 延迟2秒后再次启动蓝牙设备的刷新任务
mHandler.postDelayed(this, 2000);
}
};
// 开始扫描周围的蓝牙设备
private void beginDiscovery() {
// 如果当前不是正在搜索,则开始新的搜索任务
if (!mBluetooth.isDiscovering()) {
initBlueDevice(); // 初始化蓝牙设备列表
tv_discovery.setText("正在搜索蓝牙设备");
mBluetooth.startDiscovery(); // 开始扫描周围的蓝牙设备
}
}
// 取消蓝牙设备的搜索
private void cancelDiscovery() {
mHandler.removeCallbacks(mRefresh);
tv_discovery.setText("取消搜索蓝牙设备");
// 当前正在搜索,则取消搜索任务
if (mBluetooth.isDiscovering()) {
mBluetooth.cancelDiscovery(); // 取消扫描周围的蓝牙设备
}
}
@Override
protected void onStart() {
super.onStart();
mHandler.postDelayed(mRefresh, 50);
// 需要过滤多个动作,则调用IntentFilter对象的addAction添加新动作
IntentFilter discoveryFilter = new IntentFilter();
discoveryFilter.addAction(BluetoothDevice.ACTION_FOUND);
discoveryFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
discoveryFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
// 注册蓝牙设备搜索的广播接收器
registerReceiver(discoveryReceiver, discoveryFilter);
}
@Override
protected void onStop() {
super.onStop();
cancelDiscovery(); // 取消蓝牙设备的搜索
// 注销蓝牙设备搜索的广播接收器
unregisterReceiver(discoveryReceiver);
}
// 蓝牙设备的搜索结果通过广播返回
private BroadcastReceiver discoveryReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "onReceive action=" + action);
// 获得已经搜索到的蓝牙设备
if (action.equals(BluetoothDevice.ACTION_FOUND)) { // 发现新的蓝牙设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d(TAG, "name=" + device.getName() + ", state=" + device.getBondState());
refreshDevice(device, device.getBondState()); // 将发现的蓝牙设备加入到设备列表
} else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) { // 搜索完毕
//mHandler.removeCallbacks(mRefresh); // 需要持续搜索就要注释这行
tv_discovery.setText("蓝牙设备搜索完成");
} else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) { // 配对状态变更
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() == BluetoothDevice.BOND_BONDING) {
tv_discovery.setText("正在配对" + device.getName());
} else if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
tv_discovery.setText("完成配对" + device.getName());
mHandler.postDelayed(mRefresh, 50);
} else if (device.getBondState() == BluetoothDevice.BOND_NONE) {
tv_discovery.setText("取消配对" + device.getName());
refreshDevice(device, device.getBondState());
}
}
}
};
// 刷新蓝牙设备列表
private void refreshDevice(BluetoothDevice device, int state) {
int i;
for (i = 0; i < mDeviceList.size(); i++) {
BlueDevice item = mDeviceList.get(i);
if (item.address.equals(device.getAddress())) {
item.state = state;
mDeviceList.set(i, item);
break;
}
}
if (i >= mDeviceList.size()) {
mDeviceList.add(new BlueDevice(device.getName(), device.getAddress(), device.getBondState()));
}
mListAdapter.notifyDataSetChanged();
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//cancelDiscovery();
BlueDevice item = mDeviceList.get(position);
// 根据设备地址获得远端的蓝牙设备对象
BluetoothDevice device = mBluetooth.getRemoteDevice(item.address);
Log.d(TAG, "getBondState="+device.getBondState()+", item.state="+item.state);
if (device.getBondState() == BluetoothDevice.BOND_NONE) { // 尚未配对
BluetoothUtil.createBond(device); // 创建配对信息
} else if (device.getBondState() == BluetoothDevice.BOND_BONDED) { // 已经配对
boolean isSucc = BluetoothUtil.removeBond(device); // 移除配对信息
if (!isSucc) {
refreshDevice(device, BluetoothDevice.BOND_NONE);
}
}
}
}
六 layout中的xml文件
1 activity_bluetooth.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<CheckBox
android:id="@+id/ck_bluetooth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="@null"
android:checked="false"
android:drawableLeft="@drawable/ck_status_selector"
android:text="蓝牙关"
android:textColor="@color/black"
android:textSize="17sp" />
<TextView
android:id="@+id/tv_discovery"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="right|center"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:gravity="center"
android:text="点击设备项开始配对,再点击取消配对"
android:textColor="@color/black"
android:textSize="17sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal" >
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4"
android:gravity="center"
android:text="名称"
android:textColor="@color/black"
android:textSize="17sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="5"
android:gravity="center"
android:text="地址"
android:textColor="@color/black"
android:textSize="17sp" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:text="状态"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
<ListView
android:id="@+id/lv_bluetooth"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
2 item_bluetooth.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/tv_blue_name"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="4"
android:gravity="left|center_vertical"
android:textColor="@color/black"
android:textSize="17sp" />
<TextView
android:id="@+id/tv_blue_address"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="5"
android:gravity="center"
android:textColor="@color/black"
android:textSize="15sp" />
<TextView
android:id="@+id/tv_blue_state"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
这里首先会检测蓝牙是否打开,然后询问是否配对连接,双方获取参数状态互配连接,找两台带有蓝牙设备的机器,烧入代码观察
|