转载请注明出处 http://blog.csdn.net/shulianghan/article/details/50515359


参考 : 

-- 官方文档 : https://developer.android.com/guide/topics/connectivity/bluetooth-le.html;






1. 概述


BLE 概述

-- 版本支持Android 4.3 (API Level 18) 内置框架引入了 蓝牙低功耗方案 (Bluetooth Low Energy, BLE) 支持; 

-- 角色支持 : Android 手机只能作为 主设备 (central role), 开发者开发的 APP 可以使用其提供的 API 接口, 用于 发现设备, 遍历服务 (services),  读写服务中的特性 (characteristics). 

-- 传统蓝牙对比 : 与传统的蓝牙对比, 蓝牙低功耗方案 (Bluetooth Low Energy) 是出于更低的电量消耗考虑而设计的. 这可以使 Android 应用可以与 BLE 设备进行交流, 这些设备需要很低的电量, 如 近距离传感器, 心率测量设备, 健康设备 等等.



2. 关键术语 和 概念



(1) Generic Attribute Profile (GATT) 通用属性规范


Generic Attribute Profile (GATT) 通用属性规范 : 

-- GATT 作用 : GATT 规范是一个针对 在 BLE 连接上的, 发送 和 接收 少量数据的一个规范, 所有的现有的低功耗应用的规范都是基于这个 GATT 规范制定的.

-- 制定者 : 蓝牙技术联盟 (Bluetooth SIG) 为低功耗设备定义了许多规范, 一个 规范 (Profile) 就是 设备如何在特定的应用中工作的详述. 

-- 设备规范对应关系 : 此外, 一个设备可以实现多个规范, 如 : 一个设备可以包含一个心率检测器, 和 电量检测器.



(2) Attribute Protocol (ATT) 属性协议


Attribute Protocol (ATT) 属性协议

-- ATT 与 GATT 关系 : GATT 规范是建立在 ATT 的上一层的, 这套改改通常被称为 GATT/ATT. 

-- ATT 作用 : ATT 被用于优化 BLE 设备的运行, 为了这个目的, ATT (属性协议) 使用尽可能少的字节. 

-- ATT 唯一标识 : ATT 中的每个属性都被 一个 UUID (Universally Unique Identifier) 独一无二的进行标识, UUID 是一个 128 比特的标准的字符串 ID, 用于信息的唯一标识. 

-- ATT 属性 : ATT 中定义的属性就是 Charicteristics (特性) 和 Services (服务);



(3) Characteristic 特性


Characteristic 特性

-- Characteristic 概念 : 一个 Characteristic 特性包含了一个值 和 多个 Descriptor (描述符) 用于描述这个特性的值. 

-- 本质 : 一个特性可以被认为是一个类型, 类似于一个类.



(4) Descriptor 描述符


Descriptor 描述符

-- 作用 : 描述符 被定义为一些属性, 这些属性用于描述 Characteristic (特性) 的值. 

-- 示例 : 例如, 一个 描述符 可以说明一个 可读的描述, 一个 特性值的可接受范围, 或者 一个特性值的测量单元.



(5) Service 服务


Service 服务

-- 服务本质 : 服务是 Characteristic (特性) 的集合. 

-- 示例 : 如, 你可以有一个 名称为 "Heart Rate Monitor (心率监控)" 的服务, 包含了特性 "Heart Rate Measurement (心率测量)". 

-- 参考资料 : 你可以在 bluetooth.org 官网查询到一个基于 GATT 服务 和 规范的列表.



3. 角色 和 职责



(1) 四种角色


Android 设备 与 BLE 设备互动时, 设备的角色 和 职责

-- 中心设备 和 外围设备 : 这个角色体系适用于 BLE 连接. 中心设备角色 可以扫描, 查找广播. 外围设备角色 发送广播.

-- GATT 服务器 和 GATT 客户端 : 这个决定了两个设备之间, 一旦建议连接后, 如何进行互相通信.



(2) 中心设备 和 外围设备


BLE 连接需要两种设备都存在 : 为了理解其中的区别, 想象一下 你有一个 Android 设备 和 一个激活的 智能腕表 蓝牙设备. 手机支持作为 中心设备 角色, 智能腕表 蓝牙设备支持作为外围设备角色, 为了建立 BLE 连接, 只有外围设备 或者 只有 中心设备 都不能建立 BLE 连接.



(3) GATT 服务器 和 GATT 客户端


GATT 服务器 和 GATT 客户端 简介

-- GATT 服务器 和 GATT 客户端 角色不是固定的 : 一旦手机 和 智能腕表 设备建立了 BLE 连接, 它们开始互相交换 GATT 元数据. 根据它们之间传输的数据类型, 其中的一个会扮演 GATT 服务器的角色. 

-- 角色改变示例 : 如果 智能腕表 设备想要向手机报告传感器数据, 那么智能腕表必须当做 GATT 服务器. 如果智能腕表 想要从手机上接受更新数据, 那么 Android 手机就是 GATT 服务器.

-- 手机 和 设备 都可以作为 GATT 服务器 和 客户端 : 在本文档中使用的示例代码, 在 Android 设备上运行的 Android APP 就是 GATT 客户端, BLE 外围设备 就是 GATT 服务器. Android APP 从 GATT 服务器上获取数据, 服务器的 BLE "heart rate monitor (心率监测)" 支持 "Heart Rate Profile (心率规范 - 一种 BLE 蓝牙标准规范)". Android APP 也可以作为 GATT 服务器;



4. BLE 权限


(1) 蓝牙权限简介


Android 蓝牙权限简介

-- 权限作用 : 为了在应用中使用蓝牙功能, 必须在 AndroidManifest.xml 中 声明蓝牙权限. 所有的蓝牙通信操作都需要 蓝牙权限 来允许执行, 例如 搜索蓝牙, 蓝牙连接, 数据交互等操作.

-- 搜索设置蓝牙权限 : 如果 APP 要发起设备搜索 或者 管理 蓝牙设置, 需要 提前声明 BLUETOOTH_ADMIN 权限. 

-- 注意 : 使用 BLUETOOTH_ADMIN 权限的前提是 必须声明 BLUETOOTH 权限.



(2) 蓝牙权限简介


蓝牙权限示例

-- AndroidManifest.xml 声明蓝牙权限示例


-- 充当 BLE 设备权限 : 如果你的 APP 只需要胜任 BLE 设备的工作, 只需要如下配置 : 



(3) 动态控制 BLE 功能是否使用


动态控制 BLE 是否可用 : 不管怎样, 如果你想要让你的 APP 可以当做 BLE 设备, 但是手机不支持这个操作, 你仍然可以进行如下配置, 只是将其中的 android:required 设置成 false. 此时在运行时, 你可以使用 "PackageManager.hasSystemFeature()" 方法决定 BLE 是否可用.

//使用下面的函数决定 设备上的 BLE 功能 是否可用//此时你可以选择性的关闭 BLE 相关的功能if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {    Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();    finish();}



5. 创建 BLE


(1) 创建 BLE 简介


创建 BLE 简介

-- 验证 BLE 功能 : 在应用可以通过 BLE 交互之前, 你需要验证设备是否支持 BLE 功能, 如果支持, 确定它是可以使用的. 

-- 注意 : 这个检查只有在 下面的配置 设置为 false 时才是必须的;


-- 不支持 BLE 关闭相关功能 : 如果 Android 手机不支持 BLE 功能, 你应该优雅的 关闭 BLE 相关功能. 

-- 支持 BLE 打开蓝牙 : 如果 BLE 支持 BLE 功能, 但是设备的蓝牙是关闭的, 你可以在应用中请求打开设备的蓝牙模块. 

-- 步骤总结 : 创建 BLE 蓝牙的过程分成两个步骤, 1. 获取 BluetoothAdapter, 2. 打开 设备的蓝牙模块.



(2) 获取 BluetoothAdapter (蓝牙适配器)


获取 BluetoothAdapter 蓝牙适配器

-- BluetoothAdapter 类作用 : 所有的蓝牙活动都需要 BluetoothAdapter, BluetoothAdapter 代表了设备本身的蓝牙适配器 (蓝牙无线设备). 整个系统中只有一个 蓝牙适配器, 应用可以使用 BluetoothAdapter 对象与 蓝牙适配器硬件进行交互. 

-- 获取 BluetoothAdapter 代码示例

// 初始化蓝牙适配器final BluetoothManager bluetoothManager =        (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);mBluetoothAdapter = bluetoothManager.getAdapter();

-- 注意 : 这个方法使用了 getSystemService() 方法, 返回了一个 BluetoothManager 实例对象, 从 BluetoothManager 实例对象中可以获取 BluetoothAdapter 对象;



(3) 打开蓝牙功能


打开蓝牙

-- 检查是否可用 : 为了保证 蓝牙功能是打开的, 调用 BluetoothAdapter 的 isEnable() 方法, 检查蓝牙在当前是否可用. 如果返回 false, 说明当前蓝牙不可用. 

-- 示例代码

private BluetoothAdapter mBluetoothAdapter;...// 确认当前设备的蓝牙是否可用, // 如果不可用, 弹出一个对话框, 请求打开设备的蓝牙模块if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);}



6. 查找 BLE 设备


(1) 查找所有的 BLE 设备


查找 BLE 设备

-- 查找方法参数 : 为了搜索到 BLE 设备, 调用 BluetoothAdapter 的 startLeScan() 方法, 该方法需要一个 BluetoothAdapter.LeScanCallback 类型的参数. 你必须实现这个 LeScanCallback 接口, 因为 BLE 蓝牙设备扫描结果在这个接口中返回. 

-- 查找策略 : 蓝牙搜索是非常耗电的, 你需要遵守以下的 中断策略 和 不循环策略.

-- 中断策略 : 只要一发现蓝牙设备, 马上中断扫描.

-- 不循环策略 : 不要循环扫描, 设置一个扫描的最大时间限制. 一个设备在之前可用, 继续扫描可能会使设备不可用, 此外继续扫描会持续浪费电池电量.

-- 源码示例

/** * 搜索 和 展示 可用的蓝牙设备 的 Activity 界面 */public class DeviceScanActivity extends ListActivity {    private BluetoothAdapter mBluetoothAdapter;    private boolean mScanning;    private Handler mHandler;    // 10 秒后停止搜索    private static final long SCAN_PERIOD = 10000;    ...    private void scanLeDevice(final boolean enable) {        if (enable) {            // 在一个预先定义的时间段后停止扫描.            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);        }        ...    }...}


(2) 查找特定 BLE 设备


查找特定 BLE 设备

-- 方法调用 : 查找特定类型的外围设备, 可以调用下面的方法, 这个方法需要提供一个 UUID 对象数组, 这个 UUID 数组是 APP 支持的 GATT 服务的特殊标识.

-- 示例

startLeScan(UUID[], BluetoothAdapter.LeScanCallback)



(3) BluetoothAdapter.LeScanCallback 回调接口


扫描回调接口

-- 接口作用 : BluetoothAdapter.LeScanCallback 实现类, 在这个实现类的接口中返回 BLE 设备扫描结果;

-- 源码示例

private LeDeviceListAdapter mLeDeviceListAdapter;...// 设备扫描回调接口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();           }       });   }};


(4) 设备扫描类型


设备扫描类型 : 蓝牙设备扫描 在同一个时间扫描时, 只能扫描 BLE 设备 或者 SPP 设备中的一种, 不能同时扫描两种设备.




7. 连接到 GATT 服务


(1) 连接指定 BluetoothDevice 蓝牙设备


连接指定设备

-- 连接到 GATT 服务 : 与 BLE 设备交互的第一步是 连接到 BLE 设备中的 GATT 服务. 

-- 实现方法 : 调用 BluetoothDevice 的 connectGatt() 方法可以连接到 BLE 设备的 GATT 服务. 

-- 参数解析 : connectGatt() 方法需要三个参数, 参数一 Context 上下文对象, 参数二 boolean autoConnect 是否自动连接扫描到的蓝牙设备, 参数三 BluetoothGattCallback 接口实现类. 

-- 用法示例

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

-- 获取 BluetoothGatt 对象 : 调用 connectGatt() 方法可以连接到 BLE 设备上的 GATT 服务, 返回一个 BluetoothGatt 实例对象, 你可以使用这个对象去 管理 GATT 客户端操作. 

-- GATT 客户端操作 : Android APP 可以调用 GATT Client (客户端). BluetoothGattCallback 可以用于传递结果到 GATT 客户端, 如 连接状态 和 更进一步的 GATT Client 操作.



(2) GATT 数据交互示例


BLE 蓝牙数据交互

-- 界面 : 在下面的示例中, BLE 应用提供了一个 Activity 界面, 该 Activity 界面用于 连接, 展示数据, 展示 GATT 服务 和 设备支持的特性. 

-- BLE 蓝牙服务类 : 基于用户的输入, 这个 Activity 界面可以与一个 BluetoothLeService 的服务进行交流, 该交流的本质就是 BLE 设备的 GATT 服务 与 Android 的 BLE API 进行交流.

-- BLE 蓝牙服务类 示例代码

// BLE 设备可以通过该服务 与 Android 的 BLE API 进行互动public class BluetoothLeService extends Service {    private final static String TAG = BluetoothLeService.class.getSimpleName();    private BluetoothManager mBluetoothManager;    private BluetoothAdapter mBluetoothAdapter;    private String mBluetoothDeviceAddress;    private BluetoothGatt mBluetoothGatt;    private int mConnectionState = STATE_DISCONNECTED;    private static final int STATE_DISCONNECTED = 0;    private static final int STATE_CONNECTING = 1;    private static final int STATE_CONNECTED = 2;    public final static String ACTION_GATT_CONNECTED =            "com.example.bluetooth.le.ACTION_GATT_CONNECTED";    public final static String ACTION_GATT_DISCONNECTED =            "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";    public final static String ACTION_GATT_SERVICES_DISCOVERED =            "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";    public final static String ACTION_DATA_AVAILABLE =            "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";    public final static String EXTRA_DATA =            "com.example.bluetooth.le.EXTRA_DATA";    public final static UUID UUID_HEART_RATE_MEASUREMENT =            UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);    // BLE API 中定义的不同的回调方法.    private final BluetoothGattCallback mGattCallback =            new BluetoothGattCallback() {        @Override// BLE 设备的状态改变 连接 断开        public void onConnectionStateChange(BluetoothGatt gatt, int status,                int newState) {            String intentAction;            if (newState == BluetoothProfile.STATE_CONNECTED) {                intentAction = ACTION_GATT_CONNECTED;                mConnectionState = STATE_CONNECTED;                broadcastUpdate(intentAction);                Log.i(TAG, "连接到了 GATT 服务.");                Log.i(TAG, "尝试搜索服务:" +                        mBluetoothGatt.discoverServices());            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {                intentAction = ACTION_GATT_DISCONNECTED;                mConnectionState = STATE_DISCONNECTED;                Log.i(TAG, "于 GATT 服务断开连接.");                broadcastUpdate(intentAction);            }        }        @Override        // BLE 设备中 新的 GATT 服务被发现        public void onServicesDiscovered(BluetoothGatt gatt, int status) {            if (status == BluetoothGatt.GATT_SUCCESS) {                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);            } else {                Log.w(TAG, "发现 GATT 服务 : " + status);            }        }        @Override        // 特性读取操作返回的数据        public void onCharacteristicRead(BluetoothGatt gatt,                BluetoothGattCharacteristic characteristic,                int status) {            if (status == BluetoothGatt.GATT_SUCCESS) {                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);            }        }     ...    };...}

-- 广播发送 : 当一个特定的回调被触发, 它调用适当的 broadcastUpdate() 帮助方法, 将其当做一个 Action 操作传递出去. 

-- 注意蓝牙心率 : 这部分的数据解析 与 蓝牙心率测量 是一起被执行的.

-- 广播发送 示例代码

private void broadcastUpdate(final String action) {    final Intent intent = new Intent(action);    sendBroadcast(intent);}private void broadcastUpdate(final String action,                             final BluetoothGattCharacteristic characteristic) {    final Intent intent = new Intent(action);    // This is special handling for the Heart Rate Measurement profile. Data    // parsing is carried out as per profile specifications.// 心率监测规范的特殊处理// 数据解析在每个规范中完成    if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {        int flag = characteristic.getProperties();        int format = -1;        if ((flag & 0x01) != 0) {            format = BluetoothGattCharacteristic.FORMAT_UINT16;            Log.d(TAG, "心率格式 UINT16.");        } else {            format = BluetoothGattCharacteristic.FORMAT_UINT8;            Log.d(TAG, "心率格式 UINT8.");        }        final int heartRate = characteristic.getIntValue(format, 1);        Log.d(TAG, String.format("接收到心跳检测 : %d", heartRate));        intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));    } else {// 对于其它的规范, 写出 HEX 十六进制格式的数据        final byte[] data = characteristic.getValue();        if (data != null && data.length > 0) {            final StringBuilder stringBuilder = new StringBuilder(data.length);            for(byte byteChar : data)                stringBuilder.append(String.format("%02X ", byteChar));            intent.putExtra(EXTRA_DATA, new String(data) + "\n" +                    stringBuilder.toString());        }    }    sendBroadcast(intent);}

-- 处理广播事件 : 在 DeviceControlActivity 中处理广播事件, 示例代码 : 

// 处理 Service 发起的的不同事件// ACTION_GATT_CONNECTED: 连接到 GATT 服务.// ACTION_GATT_DISCONNECTED: 与 GATT 服务断开.// ACTION_GATT_SERVICES_DISCOVERED: 发现 GATT 服务.// ACTION_DATA_AVAILABLE: 从 BLE 设备中接收数据, 数据可以是 read 或者 notification 操作的结果.private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {    @Override    public void onReceive(Context context, Intent intent) {        final String action = intent.getAction();        if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {            mConnected = true;            updateConnectionState(R.string.connected);            invalidateOptionsMenu();        } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {            mConnected = false;            updateConnectionState(R.string.disconnected);            invalidateOptionsMenu();            clearUI();        } else if (BluetoothLeService.                ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {            // 在用户界面 显示所有支持的服务 和 特性.             displayGattServices(mBluetoothLeService.getSupportedGattServices());        } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {            displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));        }    }};



8. 读取 BLE 属性


读写属性简介

-- 读写属性前提 : Android 应用连接到了 设备中的 GATT 服务, 并且发现了 各种服务 (特性集合), 可以读写其中的属性. 

-- 读写属性代码示例 : 遍历服务 (特性集合) 和 特性, 将其展示在 UI 界面中.

public class DeviceControlActivity extends Activity {    ...    // 示范如何通过其所支持的 GATT 遍历 服务 (Services) 和 特性 (Characteristics)    // 在这个示例中, 我们将查询出的数据填充到 UI 界面中的 ExpandableListView 中    private void displayGattServices(List gattServices) {        if (gattServices == null) return;        String uuid = null;        String unknownServiceString = getResources().                getString(R.string.unknown_service);        String unknownCharaString = getResources().                getString(R.string.unknown_characteristic);        ArrayList> gattServiceData =                new ArrayList>();        ArrayList>> gattCharacteristicData                = new ArrayList>>();        mGattCharacteristics =                new ArrayList>();        // 遍历 GATT 服务        for (BluetoothGattService gattService : gattServices) {            HashMap currentServiceData =                    new HashMap();            uuid = gattService.getUuid().toString();            currentServiceData.put(                    LIST_NAME, SampleGattAttributes.                            lookup(uuid, unknownServiceString));            currentServiceData.put(LIST_UUID, uuid);            gattServiceData.add(currentServiceData);            ArrayList> gattCharacteristicGroupData =                    new ArrayList>();// 获取服务中的特性集合            List gattCharacteristics =                    gattService.getCharacteristics();            ArrayList charas =                    new ArrayList();           // 循环遍历特性集合            for (BluetoothGattCharacteristic gattCharacteristic :                    gattCharacteristics) {                charas.add(gattCharacteristic);                HashMap currentCharaData =                        new HashMap();                uuid = gattCharacteristic.getUuid().toString();                currentCharaData.put(                        LIST_NAME, SampleGattAttributes.lookup(uuid,                                unknownCharaString));                currentCharaData.put(LIST_UUID, uuid);                gattCharacteristicGroupData.add(currentCharaData);            }            mGattCharacteristics.add(charas);            gattCharacteristicData.add(gattCharacteristicGroupData);         }    ...    }...}




9. 接收 GATT 通知


GATT 通知简介

-- 特性改变通知 : 当 BLE 设备中的一些特殊的特性改变, 需要通知与之连接的 Android BLE 应用.

-- 代码示例 : 使用 setCharacteristicNotification() 方法为特性设置通知.

private BluetoothGatt mBluetoothGatt;BluetoothGattCharacteristic characteristic;boolean enabled;...// 设置是否监听某个特性改变mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);...BluetoothGattDescriptor descriptor = characteristic.getDescriptor(        UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);mBluetoothGatt.writeDescriptor(descriptor);

-- 特性改变回调 : 一但特性开启了改变通知监听, 如果特性发生了改变, 就会回调 BluetoothGattCallback 接口中的 onCharacteristicChanged() 方法.

@Override// 特性通知public void onCharacteristicChanged(BluetoothGatt gatt,        BluetoothGattCharacteristic characteristic) {    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);}



10. 关闭 APP 中的 BLE 连接



关闭 BLE 设备连接

-- 关闭方法 : 一旦结束了 BLE 设备的使用, 调用 BluetoothGatt 的 close() 方法, 关闭 BLE 连接, 释放相关的资源.

-- 关闭示例

public void close() {    if (mBluetoothGatt == null) {        return;    }    mBluetoothGatt.close();    mBluetoothGatt = null;}




转载请注明出处 http://blog.csdn.net/shulianghan/article/details/50515359

更多相关文章

  1. Android(安卓)App耗电量统计
  2. Android(安卓)activity exported属性理解
  3. Android(安卓)低功耗蓝牙
  4. 【Android(安卓)开发教程】保存到内部存储设备
  5. Android(安卓)1.5: 飞行模式分析
  6. mac如何android设备上运行react-native
  7. Android开发之Android的核心服务
  8. Android蓝牙系统分析
  9. android ndk build

随机推荐

  1. Android用Application设置全局变量以及使
  2. 如何离线安装android的sdk
  3. Android学习笔记之Android包、ADB介绍
  4. android 各种控件颜色值的设置(使用Drawab
  5. android Adapter综合介绍
  6. Android(安卓)基本控件及表单三大控件,事
  7. 详解 Android(安卓)的 Activity 组件
  8. android:shape的使用
  9. 关于android和java环境和编译的一些基本
  10. Android之Adapter用法总结