Android BLE 蓝牙编程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android BLE 蓝牙编程相关的知识,希望对你有一定的参考价值。
大家中秋快乐啊~~哈哈,今天继续工程项目吧!
上篇我们已经实现了蓝牙设备的扫描,本篇我们来通过list展示扫描到的设备并
实现点击连接。
先贴出上篇的完整的MainActivity的方法:
package com.wbnq.shouhuan; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothManager; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private Button saomiao , duanzhen , changzhen , buting , tingxia; private TextView jibu , dianliang , lianjiezhuangtai; BluetoothAdapter bluetoothAdapter; List<BluetoothDevice> deviceList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); //蓝牙管理,这是系统服务可以通过getSystemService(BLUETOOTH_SERVICE)的方法获取实例 BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); //通过蓝牙管理实例获取适配器,然后通过扫描方法(scan)获取设备(device) bluetoothAdapter = bluetoothManager.getAdapter(); } private void initView() { saomiao = (Button) findViewById(R.id.saomiao); duanzhen = (Button) findViewById(R.id.zhendong); changzhen = (Button) findViewById(R.id.changzhen); buting = (Button) findViewById(R.id.buting); tingxia = (Button) findViewById(R.id.tingxia); jibu = (TextView) findViewById(R.id.jibu); dianliang = (TextView) findViewById(R.id.dianliang); lianjiezhuangtai = (TextView) findViewById(R.id.lianjiezhuangtai); saomiao.setOnClickListener(this); duanzhen.setOnClickListener(this); changzhen.setOnClickListener(this); buting.setOnClickListener(this); tingxia.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.saomiao: //开始扫描前开启蓝牙 Intent turn_on = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(turn_on, 0); Toast.makeText(MainActivity.this, "蓝牙已经开启", Toast.LENGTH_SHORT).show(); Thread scanThread = new Thread(new Runnable() { @Override public void run() { Log.i("TAG", "run: saomiao ..."); saomiao(); } }); scanThread.start(); break; case R.id.zhendong: break; case R.id.changzhen: break; case R.id.buting: break; case R.id.tingxia: break; } } public void saomiao(){ deviceList.clear(); bluetoothAdapter.startLeScan(callback); } //扫描回调 public BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice bluetoothDevice, int i, byte[] bytes) { Log.i("TAG", "onLeScan: " + bluetoothDevice.getName() + "/t" + bluetoothDevice.getAddress() + "/t" + bluetoothDevice.getBondState()); //重复过滤方法,列表中包含不该设备才加入列表中,并刷新列表 if (!deviceList.contains(bluetoothDevice)) { //将设备加入列表数据中 deviceList.add(bluetoothDevice); } } }; }
这是上篇的,没有在log下看到扫描消息的小伙伴看看出啥问题了吧~~
好了,第二篇正式开始。
先贴出来MyAdapter的代码(这不是本节重点,请参阅前面关于adapter的写法)
package com.wbnq.shouhuan; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import java.util.List; /** * Created by guwei on 16-9-2. */ public class MyAdapter extends BaseAdapter{ public List<BluetoothDevice> mlist; private LayoutInflater mInflater; public MyAdapter(Context context , List<BluetoothDevice> list){ mlist = list; mInflater = LayoutInflater.from(context); } //获取传入的数组大小 @Override public int getCount() { return mlist.size(); } //获取第N条数据 @Override public Object getItem(int i) { return mlist.get(i); } //获取item id @Override public long getItemId(int i) { return i; } //主要方法 @Override public View getView(int i, View view, ViewGroup viewGroup) { ViewHolder viewHolder = new ViewHolder(); if(view == null){ //首先为view绑定布局 view = mInflater.inflate(R.layout.devices_item , null); viewHolder.name = (TextView) view.findViewById(R.id.bluetoothname); viewHolder.uuid = (TextView) view.findViewById(R.id.uuid); viewHolder.status = (TextView) view.findViewById(R.id.status); view.setTag(viewHolder); }else{ viewHolder = (ViewHolder) view.getTag(); } BluetoothDevice bd = mlist.get(i); viewHolder.name.setText(bd.getName()); viewHolder.uuid.setText(bd.getAddress()); //viewHolder.status.setText(R.string.noconnect); return view; } class ViewHolder{ private TextView name , uuid , status; } }
item布局代码 devices_item.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/bluetoothicon" android:layout_width="37dp" android:layout_height="50dp" android:background="@mipmap/ic_bluetooth_black_36dp" /> <TextView android:id="@+id/bluetoothname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_toRightOf="@+id/bluetoothicon" android:text="name" android:textColor="#000000" android:textSize="19dp" /> <TextView android:id="@+id/uuid" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/bluetoothname" android:layout_marginLeft="5dp" android:layout_marginTop="5dp" android:layout_toRightOf="@id/bluetoothicon" android:text="uuid" android:textSize="15dp" /> <TextView android:id="@+id/status" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="5dp" android:layout_toRightOf="@id/bluetoothname" android:text="" android:textColor="#ff0000" /> </RelativeLayout>
在布局文件中添加一下listview控件
并且在MainActivity添加监听。
然后在扫描回调中添加list.setAdapter(new MyAdapter(MainActivity.this , deviceList));
就可以顺利的将得到的列表用list展示出来啦~~
//扫描回调 public BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice bluetoothDevice, int i, byte[] bytes) { Log.i("TAG", "onLeScan: " + bluetoothDevice.getName() + "/t" + bluetoothDevice.getAddress() + "/t" + bluetoothDevice.getBondState()); //重复过滤方法,列表中包含不该设备才加入列表中,并刷新列表 if (!deviceList.contains(bluetoothDevice)) { //将设备加入列表数据中 deviceList.add(bluetoothDevice); list.setAdapter(new MyAdapter(MainActivity.this , deviceList)); } } };
看下效果:点击扫描后
想要连接设备就要在list的监听事件中添加下面的方法:
这里的bluetoothdevice就是用来存放每个item的内容的
上篇也说明了,想要连接设备就要使用bluetoothDevice的connectGatt方法:
该方法包含三个参数:
参数一 : context 上下文 这里传 MainActivity即可
参数二: autoConnect 是否自动重连 一般填 false
参数三: gattcallback 是BluetoothGattCallback回调,该方法由系统提供,我们只需要重写方法即可
该方法的返回值为bluetoothGatt类型。
//item 监听事件 list.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { bluetoothDevice = deviceList.get(i); //连接设备的方法,返回值为bluetoothgatt类型 bluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, gattcallback); lianjiezhuangtai.setText("连接" + bluetoothDevice.getName() + "中..."); } });
重写gatt回调方法:
BluetoothGattCallback
private BluetoothGattCallback gattcallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorRead(gatt, descriptor, status); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorWrite(gatt, descriptor, status); } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { super.onReliableWriteCompleted(gatt, status); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { super.onReadRemoteRssi(gatt, rssi, status); } @Override public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { super.onMtuChanged(gatt, mtu, status); } } ;
我们这里主要用到
onConnectionStateChange
onServicesDiscovered
onCharacteristicWrite
首先通过onConnectionStateChange获取连接的状态:
public void onConnectionStateChange(BluetoothGatt gatt, int status, final int newState) { super.onConnectionStateChange(gatt, status, newState); runOnUiThread(new Runnable() { @Override public void run() { String status; switch (newState) { //已经连接 case BluetoothGatt.STATE_CONNECTED: lianjiezhuangtai.setText("已连接"); //该方法用于获取设备的服务,寻找服务 //bluetoothGatt.discoverServices(); break; //正在连接 case BluetoothGatt.STATE_CONNECTING: lianjiezhuangtai.setText("正在连接"); break; //连接断开 case BluetoothGatt.STATE_DISCONNECTED: lianjiezhuangtai.setText("已断开"); break; //正在断开 case BluetoothGatt.STATE_DISCONNECTING: lianjiezhuangtai.setText("断开中"); break; } //pd.dismiss(); } }); }
参数中的 newstate就是连接的状态。
连接状态一共分成四种:
一: 已连接
二: 正在连接
三: 正在断开
四: 已断开
不过实际使用中正在连接和正在断开的状态并没有真正的返回给我们的程序,
不过两个状态已经够我们使用了~
连接状态通过连接状态的textview展示一下,我们现在快来看看效果吧~
整体代码:
MainActivity.class:
package com.wbnq.shouhuan; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothManager; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private Button saomiao , duanzhen , changzhen , buting , tingxia; private TextView jibu , dianliang , lianjiezhuangtai; private ListView list; BluetoothAdapter bluetoothAdapter; BluetoothGatt bluetoothGatt; List<BluetoothDevice> deviceList = new ArrayList<>(); BluetoothDevice bluetoothDevice; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); //蓝牙管理,这是系统服务可以通过getSystemService(BLUETOOTH_SERVICE)的方法获取实例 BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); //通过蓝牙管理实例获取适配器,然后通过扫描方法(scan)获取设备(device) bluetoothAdapter = bluetoothManager.getAdapter(); } private void initView() { saomiao = (Button) findViewById(R.id.saomiao); duanzhen = (Button) findViewById(R.id.zhendong); changzhen = (Button) findViewById(R.id.changzhen); buting = (Button) findViewById(R.id.buting); tingxia = (Button) findViewById(R.id.tingxia); list = (ListView) findViewById(R.id.list); jibu = (TextView) findViewById(R.id.jibu); dianliang = (TextView) findViewById(R.id.dianliang); lianjiezhuangtai = (TextView) findViewById(R.id.lianjiezhuangtai); saomiao.setOnClickListener(this); duanzhen.setOnClickListener(this); changzhen.setOnClickListener(this); buting.setOnClickListener(this); tingxia.setOnClickListener(this); //item 监听事件 list.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { bluetoothDevice = deviceList.get(i); //连接设备的方法,返回值为bluetoothgatt类型 bluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, gattcallback); lianjiezhuangtai.setText("连接" + bluetoothDevice.getName() + "中..."); } }); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.saomiao: //开始扫描前开启蓝牙 Intent turn_on = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(turn_on, 0); Toast.makeText(MainActivity.this, "蓝牙已经开启", Toast.LENGTH_SHORT).show(); Thread scanThread = new Thread(new Runnable() { @Override public void run() { Log.i("TAG", "run: saomiao ..."); saomiao(); } }); scanThread.start(); break; case R.id.zhendong: break; case R.id.changzhen: break; case R.id.buting: break; case R.id.tingxia: break; case R.id.list: break; } } public void saomiao(){ deviceList.clear(); bluetoothAdapter.startLeScan(callback); } //扫描回调 public BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice bluetoothDevice, int i, byte[] bytes) { Log.i("TAG", "onLeScan: " + bluetoothDevice.getName() + "/t" + bluetoothDevice.getAddress() + "/t" + bluetoothDevice.getBondState()); //重复过滤方法,列表中包含不该设备才加入列表中,并刷新列表 if (!deviceList.contains(bluetoothDevice)) { //将设备加入列表数据中 deviceList.add(bluetoothDevice); list.setAdapter(new MyAdapter(MainActivity.this , deviceList)); } } }; private BluetoothGattCallback gattcallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, final int newState) { super.onConnectionStateChange(gatt, status, newState); runOnUiThread(new Runnable() { @Override public void run() { String status; switch (newState) { //已经连接 case BluetoothGatt.STATE_CONNECTED: lianjiezhuangtai.setText("已连接"); //该方法用于获取设备的服务,寻找服务 bluetoothGatt.discoverServices(); break; //正在连接 case BluetoothGatt.STATE_CONNECTING: lianjiezhuangtai.setText("正在连接"); break; //连接断开 case BluetoothGatt.STATE_DISCONNECTED: lianjiezhuangtai.setText("已断开"); break; //正在断开 case BluetoothGatt.STATE_DISCONNECTING: lianjiezhuangtai.setText("断开中"); break; } //pd.dismiss(); } }); } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorRead(gatt, descriptor, status); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorWrite(gatt, descriptor, status); } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { super.onReliableWriteCompleted(gatt, status); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { super.onReadRemoteRssi(gatt, rssi, status); } @Override public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { super.onMtuChanged(gatt, mtu, status); } } ; }
实现效果:
好啦!!我们功能已经实现了一大部分了呢!!
下节我们就来获取手环中
我走的步数 , 和电池的电量吧~~
大家加油啦~~~
以上是关于Android BLE 蓝牙编程的主要内容,如果未能解决你的问题,请参考以下文章
QT应用编程: 编写低功耗BLE蓝牙调试助手(Android系统APP)
QT应用编程: 编写低功耗BLE蓝牙调试助手(Android系统APP)