您的位置:首页 > 编程语言

代码流程分析二:Settings-蓝牙分析-新增rawgelWhile分析二

2015-05-04 19:17 393 查看
一:流程图已经分析







二:代码的分析

进入蓝牙界面,点击做软键做出的处理是弹出一个新的界面->流程如下

onResume();

给listView设置适配器,他里面放的是查询出来的可用设备

从shardpreference中取的mac地址值,

查询设备,她的原理是定时查询10秒后停止查询,在这10秒之间就查询回调函数的设备,也就是一进来查询10秒停止查询。

然后发一个消息:如果mac地址不为空,空linearLayout可见,设置mac地址,设置连接。否则就是mac地址为空的话,显示listView,并且里面放适配器,隔1秒给自己发一次这个消息。

如果有了之前连接的设备,查询连接以后。上来显示的是linearLayout里面放的是地址,和显示的连接,点击,注销了

前提是之前连接过这个设备的时候。

情形一:什么都没做的时候,进入界面,会查询设备,如果设备开着,配对成功了,会显示设备的地址和discoonected,上面 会查询的圈圈,10S之后停止。

流程:onCreate-->onResume-->scanLeDevice-->定时10S查询,按理说走回调方法mBluetoothAdapter.startLeScan(mLeScanCallback);但是这个时候没走为什么?谁能告诉我,而且后面listView显示的设备的地址是怎么查出来的。bluetoothCODAService收到广播,停止查询。-->Handler_delayed.sendEmptyMessage(0);1S刷新一遍,看mac地址是空,因为没有保存过这个地址,刚上来。但是现在居然可以了走了回调函数。所以显示listView,显示listView需要适配器,设备地址和disconnected-->点击这个listView的时候会刷新适配器,删除设备就是listView是空的,设置linearlayout显示出来,显示设备地址和连接状态,同时发送广播将设备的信息发送过去。后续的操作,稍等。。。在情形六分析了

情形一:连接成功,按了返回,或者关机键,退出去。home还是会显示连接状态,现在进去之后会自动连接,也就是进去会显示已经连linearlayout

流程一没进去在home的时候:后台服务查询出来。

流程二进去之后:onCreate()-->onResume()-->scanDevices()查询设备(10S定时为什么没走回调函数)-->发送一个消息每秒发送一次给自己。现在说显示界面,因为之前保存过了mac地址,linearlayout是可见的里面mac_adress不为空,显示设备adress,显示connected-->查询设备那10S之内,开始查询,发送广播,bluetoothCODAService这个接受广播action是"BluetoothScan"停止查询,那么问题来了,为什么没走查询回调函数,为什么连接了之后进去也查询了,但是不走回调函数

情形二:显示的是设备地址,connected,这个时候点击,点击的是linearlayout,会消失什么都没有了,意思就是断开连接了null

流程:走的linearlayout的点击事件,将adress和adress_old值为null,就是没值了,不存值了。-->Handler_delayed.sendEmptyMessage(0);1S刷新一遍,看mac地址因为点击了你给成null了所以刷新的时候会显示listView但是listView没有数据,所以看见就是什么都没有。-->发送广播bluetoothCODAService这个接受广播"BluetoothDissconnected"停止查询,屏幕变暗就走onpause(),停止查询设备

情形三:屏幕亮了之后会查询转一圈,什么也不显示,按园设备没反映。

流程:走onresume()-->scanDevices()-->bluetoothCODAService这个接受广播action是"BluetoothScan"然后停止查询。那么问题来了为啥没走发送消息,是因为mac地址为null?一会验证。

情形四:这个时候点击scan查询按钮,同时需要按住圆的那个,会显示设备的地址,下面是disconnected,这个下面的是listView

流程:走onresume()-->scanDevices()-->bluetoothCODAService这个接受广播action是"BluetoothScan"然后停止查询。会继续走回调函数-->给listView中填充设备,为什么这个会走回调函数啊?

情形五:这个时候屏幕变暗,再次打开什么也没有就是走了onpase()断开了连接,停止查询了

情形六:当我们点击连接的时候,直接变成了连接状态。linearlayout,

这个时候会走回调,也就是说,回调函数是在显示listView的时候才调用,显示linearlayout的时候不调用回调函数

流程:点击listView-->发送广播-->设置linear可见。bluetoothCODAService接到广播“BluetoothConnect”是这个动作-->mGattCallback走回调函数-->

方法一:onConnectionStateChange第一条if(连接)停止查询设备,第二个if(连接)discoverServices()-->发送icon广播

方法二:onServicesDiscovered-->displayGattServices_Battery(getSupportedGattServices());走电池电量-->

方法三:onCharacteristicRead

方法四:onCharacteristicChanged-->displayData()处理数据第一个if里面处理的方法是:连上设备之后点下去,对讲,点击,长按。第二个if的意思是不点击,走的方法-->Handler_Battery.sendEmptyMessage(0)-->displayGattServices-->存了值put了adress值和adress_old了值

情形七:当我们之前已经连接好了,现在关机状态,开机之后home会显示已经连接状态

流程:单纯的是开启了个服务来管理的

开机走的一个广播接受者:BootCompletedReceiver会启动BluetoothCODAService这个服务---->服务走oncreate->onStart会判断之前存的old的mac地址值不为null的情况下-->

scanLeDevice-->走回调函数跟前面一样,区别是之前的回调函数中是给适配器中加了设备,因为是要考虑listView的情况,这个下面是做了判断,如果现在的mac地址值和保存的mac地址值一样就走连接的回调函数BluetoothGattCallback又回到了接收到广播之后的处理了,所以这个时候情形6一样了。将现在的设备的各种值什么的存储一遍。

以上就是基本的流程功能:

BUG1:会显示2个设备,一个是连接状态另一个是不连接状态,问题是假如是连接状态,我再点查询(10S),在10S内我把设备关了再开,同时点击停止查询。会显示断开,我再打开设备就是出现2个状态,点一个就又出现问题了。。。。连上以后开关设备,再点击查询就出来2个了。连接的情况下,点击查询将设备关了再开,会出现2个,但是过一会自己没了,再点击连接就连不上了。

BUG2:listView显示未连接,点击连接,马上断开,不会保存值,下次开机连接不上。值为空

解决办法:将linearlayout里面的old的值put为null这句话注掉,为什么注掉,因为之前连接好了,shard有个缓存的原理,避免她的失误就是存了,不要值为空,再存的时候还是之前的值

BUG3:当我连上设备之后,长按设备会发生对讲,但是如果这个时候关闭这个设备,或者,在手机端点击断开连接,或者关闭蓝牙,这三种情况都是出现的问题是只走了按下的down事件,没走up上的事件,处理的方法:

先将下面pttkey的值保存起来,然后在断开设备的那个地方走这句话

else if(newState == BluetoothProfile.STATE_DISCONNECTED){

Log.v("lwn","state2="+BluetoothProfile.STATE_DISCONNECTED);

editor.putString("RadgerWheel_Connect_Address", "null");

editor.commit();

//[liuweinan][2015-5-7][add][S]

if(ptt_key_==1){

Intent intent2 = new Intent("com.android.bluetooth.support.BTPTTKey");

Log.v("lwn","zoul up");

intent2.putExtra("event_action", KeyEvent.ACTION_UP);

sendBroadcast(intent2);

}

//[liuweinan][2015-5-7][add][E]

}就是给ptt发送广播,告诉它将没有发送的up广播发送过去。

同理在接收的那,received蓝牙开关和断开连接都会给这个服务发送广播消息,所以在这处理同样的代码就可以。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

再分析RadgerWheel_Connect_Address的作用:是当前的设备

RadgerWheel_Connect_Address_old的作用:用处是,关机之后回来,还能继续连上。是保存了当前的设备的值,保存了就一直保存着,不给它值为null,就算断开了也是前面那个管着,值一直保存着,如果有新的设备进来会直接保存新的设备的值。

再说最上面的导航条是怎么来的?但是为什么这个菜单按钮是加到了右上脚?

Android2.3或更低的版本会在每次Menu打开的时候调用一次onPrepareOptionsMenu().

Android3.0及以上版本默认menu是打开的,所以必须调用invalidateOptionsMenu()方法,然后系统将调用onPrepareOptionsMenu()执行update操作。

@Override

public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.main, menu);

if (!mScanning) {

menu.findItem(R.id.menu_stop).setVisible(false);

menu.findItem(R.id.menu_scan).setVisible(true);

menu.findItem(R.id.menu_refresh).setActionView(null);

menu.findItem(R.id.menu_refresh).setVisible(false);只显示查询

} else {

menu.findItem(R.id.menu_stop).setVisible(true);

menu.findItem(R.id.menu_scan).setVisible(false);

menu.findItem(R.id.menu_refresh).setVisible(true);

menu.findItem(R.id.menu_refresh).setActionView(

R.layout.actionbar_indeterminate_progress);显示停止显示进度条

}

return true;

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

switch (item.getItemId()) {

case R.id.menu_scan:

mLeDeviceListAdapter.clear();查询操作

scanLeDevice(true);

break;

case R.id.menu_stop:

scanLeDevice(false);停止操作

break;

}

return true;

}

新加的内容,就是服务连接那块:



Android4.3 蓝牙BLE初步

分类: Android

一、关键概念:

Generic
Attribute Profile (GATT)

通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。

Attribute
Protocol (ATT)

GATT是基于ATT
Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。

Characteristic

Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。

Descriptor

对Characteristic的描述,例如范围、计量单位等。

Service

Characteristic的集合。例如一个service叫做“Heart
Rate Monitor”,它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic。

二、角色和职责:

Android设备与BLE设备交互有两组角色:

中心设备和外围设备(Central
vs. peripheral);

GATT
server vs. GATT client.

Central
vs. peripheral:

中心设备和外围设备的概念针对的是BLE连接本身。Central角色负责scan
advertisement。而peripheral角色负责make advertisement。

GATT
server vs. GATT client:

这两种角色取决于BLE连接成功后,两个设备间通信的方式。

举例说明:

现有一个活动追踪的BLE设备和一个支持BLE的Android设备。Android设备支持Central角色,而BLE设备支持peripheral角色。创建一个BLE连接需要这两个角色都存在,都仅支持Central角色或者都仅支持peripheral角色则无法建立连接。

当连接建立后,它们之间就需要传输GATT数据。谁做server,谁做client,则取决于具体数据传输的情况。例如,如果活动追踪的BLE设备需要向Android设备传输sensor数据,则活动追踪器自然成为了server端;而如果活动追踪器需要从Android设备获取更新信息,则Android设备作为server端可能更合适。

三、权限及feature:

和经典蓝牙一样,应用使用蓝牙,需要声明BLUETOOTH权限,如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限:

<uses-permission
android:name="android.permission.BLUETOOTH"/>

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

除了蓝牙权限外,如果需要BLE
feature则还需要声明uses-feature:

<uses-feature
android:name="android.hardware.bluetooth_le" android:required="true"/>

按时required为true时,则应用只能在支持BLE的Android设备上安装运行;required为false时,Android设备均可正常安装运行,需要在代码运行时判断设备是否支持BLE
feature:

//
Use this check to determine whether BLE is supported on the device. Then

// you can selectively disable BLE-related features.

if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {

Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();

finish();

}

四、启动蓝牙:

在使用蓝牙BLE之前,需要确认Android设备是否支持BLE
feature(required为false时),另外要需要确认蓝牙是否打开。

如果发现不支持BLE,则不能使用BLE相关的功能。如果支持BLE,但是蓝牙没打开,则需要打开蓝牙。

打开蓝牙的步骤:

1、获取BluetoothAdapter

BluetoothAdapter是Android系统中所有蓝牙操作都需要的,它对应本地Android设备的蓝牙模块,在整个系统中BluetoothAdapter是单例的。当你获取到它的示例之后,就能进行相关的蓝牙操作了。

获取BluetoothAdapter代码示例如下:

//
Initializes Bluetooth adapter.

final BluetoothManager bluetoothManager =

(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

mBluetoothAdapter = bluetoothManager.getAdapter();

注:这里通过getSystemService获取BluetoothManager,再通过BluetoothManager获取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API
level 18)。

2、判断是否支持蓝牙,并打开蓝牙

获取到BluetoothAdapter之后,还需要判断是否支持蓝牙,以及蓝牙是否打开。

如果没打开,需要让用户打开蓝牙:

private
BluetoothAdapter mBluetoothAdapter;

...

// Ensures Bluetooth is available on the device and it is enabled. If not,

// displays a dialog requesting user permission to enable Bluetooth.

if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {

Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

}

五、搜索BLE设备:

通过调用BluetoothAdapter的startLeScan()搜索BLE设备。调用此方法时需要传入BluetoothAdapter.LeScanCallback参数。

因此你需要实现 BluetoothAdapter.LeScanCallback接口,BLE设备的搜索结果将通过这个callback返回。

由于搜索需要尽量减少功耗,因此在实际使用时需要注意:

1、当找到对应的设备后,立即停止扫描;

2、不要循环搜索设备,为每次搜索设置适合的时间限制。避免设备不在可用范围的时候持续不停扫描,消耗电量。

搜索的示例代码如下:

/**

* Activity for scanning and displaying available BLE devices.

*/

public class DeviceScanActivity extends ListActivity {

private BluetoothAdapter mBluetoothAdapter;

private boolean mScanning;

private Handler mHandler;

// Stops scanning after 10 seconds.

private static final long SCAN_PERIOD = 10000;

...

private void scanLeDevice(final boolean enable) {

if (enable) {

// Stops scanning after a pre-defined scan period.

mHandler.postDelayed(new Runnable() {

@Override

public void run() {

mScanning = false;

mBluetoothAdapter.stopLeScan(mLeScanCallback);

}

}, SCAN_PERIOD);

mScanning = true;

mBluetoothAdapter.startLeScan(mLeScanCallback);

} else {

mScanning = false;

mBluetoothAdapter.stopLeScan(mLeScanCallback);

}

...

}

...

}

如果你只需要搜索指定UUID的外设,你可以调用 startLeScan(UUID[],
BluetoothAdapter.LeScanCallback)方法。

其中UUID数组指定你的应用程序所支持的GATT
Services的UUID。

BluetoothAdapter.LeScanCallback的实现示例如下:

private
LeDeviceListAdapter mLeDeviceListAdapter;

...

// Device scan callback.

private BluetoothAdapter.LeScanCallback mLeScanCallback =

new BluetoothAdapter.LeScanCallback() {

@Override

public void onLeScan(final BluetoothDevice device, int rssi,

byte[] scanRecord) {

runOnUiThread(new Runnable() {

@Override

public void run() {

mLeDeviceListAdapter.addDevice(device);

mLeDeviceListAdapter.notifyDataSetChanged();

}

});

}

};

注意:搜索时,你只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索。

六、连接GATT Server:

两个设备通过BLE通信,首先需要建立GATT连接。这里我们讲的是Android设备作为client端,连接GATT
Server。

连接GATT
Server,你需要调用BluetoothDevice的connectGatt()方法。此函数带三个参数:Context、autoConnect(boolean)和BluetoothGattCallback对象。调用示例:

mBluetoothGatt
= device.connectGatt(this, false, mGattCallback);

函数成功,返回BluetoothGatt对象,它是GATT
profile的封装。通过这个对象,我们就能进行GATT Client端的相关操作。BluetoothGattCallback用于传递一些连接状态及结果。

BluetoothGatt常规用到的几个操作示例:

connect()
:连接远程设备。

discoverServices()
: 搜索连接设备所支持的service。

disconnect():断开与远程设备的GATT连接。

close():关闭GATT
Client端。

readCharacteristic(characteristic)
:读取指定的characteristic。

setCharacteristicNotification(characteristic,
enabled) :设置当指定characteristic值变化时,发出通知。

getServices()
:获取远程设备所支持的services。

等等。

注:

1、某些函数调用之间存在先后关系。例如首先需要connect上才能discoverServices。

2、一些函数调用是异步的,需要得到的值不会立即返回,而会在BluetoothGattCallback的回调函数中返回。例如discoverServices与onServicesDiscovered回调,readCharacteristic与onCharacteristicRead回调,setCharacteristicNotification与onCharacteristicChanged回调等。

以上就是新增功能的所有流程,全部分析完毕。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: