事务的难度远远低于对事物的恐惧

0.前言

Android BLE蓝牙配置全流程(一) 附APP源码 中已经完成了前期的准备工作,在这里我们得到了需要连接的蓝牙设备的名字和地址,需要完成蓝牙设备的连接和数据传输功能。

1.初始化界面

首先需要完成对这个界面包含的控件进行初始化,代码如下:

private TextView text1, text2;
private EditText editText;
private Button btn_send;
private String status = "Disconnected";
private final static String TAG = "hello";//界面初始化private void initView() {text1 = findViewById(R.id.text1);text2 = findViewById(R.id.text2);editText = findViewById(R.id.edit_text);btn_send = findViewById(R.id.btn_send);text1.setText("状态:" + status);btn_send.setOnClickListener(this);}

控件text1中显示目前的连接状态,控件text2中显示接收到的数据,控件edittext中输入要发送的数据,控件btn_send是发送按钮

2.获取前一个界面传来的数据

首先得到前一个界面传来的数据,代码如下:

public static String EXTRAS_DEVICE_NAME = "DEVICE_NAME";
public static String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";private Bundle bundle;
private String name;
private String address;bundle = getIntent().getExtras();
name = bundle.getString(EXTRAS_DEVICE_NAME);
address = bundle.getString(EXTRAS_DEVICE_ADDRESS);

name中存放蓝牙设备的名字,address中存放蓝牙设备的地址。

3.创建一个服务类并继承Service

本文中创建了一个BlutoothBLEService 并继承了Service,完成蓝牙设备的初始化、连接、断开连接、读取特征值、写入特征值、设置特征值变化通知以及获取已连接蓝牙的所有服务等操作。

public class BlutoothBLEService extends Service {...............................
}

3.1 蓝牙设备初始化

public final static String ACTION_GATT_CONNECTED = "com.example.bluebledemo.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED = "com.example.bluebledemo.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.bluebledemo.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE = "com.example.bluebledemo.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA = "com.example.bluebledemo.EXTRA_DATA";private final static int STATE_DISCONNECTED = 0;
private final static int STATE_CONNECTING = 1;
private final static int STATE_CONNECTED = 2;private final static String TAG = "hello";private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;//蓝牙初始化 在第二个界面中的ServiceConnection中调用
public boolean initialize() {if (mBluetoothManager == null) {mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);if (mBluetoothManager == null) {Log.i(TAG, "initialize: mBluetoothManager 初始化失败");return false;}}mBluetoothAdapter = mBluetoothManager.getAdapter();if (mBluetoothAdapter == null) {Log.i(TAG, "initialize: mBluetoothAdapter 初始化失败");return false;}return true;
}

上面代码是在第二个界面成功绑定这个服务之后,在回调函数ServiceConnection中被执行,下文将详细介绍,这里先把这个服务详细的说清楚。

3.2 蓝牙设备的连接

private BluetoothGatt mBluetoothGatt;//蓝牙连接外围设备
public boolean connect(final String address) {if (mBluetoothAdapter == null || address == null) {Log.i(TAG, "connect: BLE not init");return false;}if (mBluetoothDeviceAddress != null && mBluetoothGatt != null && mBluetoothDeviceAddress.equals(address)) {Log.i(TAG, "connect: Trying to use an existing mBluetoothGatt for connection");if (mBluetoothGatt.connect()) {mConnectionState = STATE_CONNECTING;return true;} else {return false;}}final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);if (device == null) {Log.i(TAG, "connect: device not found");return false;}mBluetoothGatt = device.connectGatt(this, false, mGattCallback);Log.i(TAG, "connect: Trying to create a connection");mBluetoothDeviceAddress = address;mConnectionState = STATE_CONNECTING;return true;
}

在第二个界面中会创建一个BlutoothBLEService类的对象,然后调用这个方法并传入地址,即可连接成功。mBluetoothGatt = device.connectGatt(this, false, mGattCallback)通过绑定回调函数,本节的后续操作都可在回调函数中完成相应的操作。

3.3 蓝牙设备取消连接

//取消连接
public void disconnect() {if (mBluetoothAdapter == null || mBluetoothGatt == null) {Log.i(TAG, "disconnect: BLE not init");return;}mBluetoothGatt.disconnect();
}//关闭所有蓝牙连接
public void close() {if (mBluetoothGatt == null) {return;}mBluetoothGatt.close();mBluetoothGatt = null;
}

同样通过BlutoothBLEService类的对象调用这个方法即可取消连接。

3.4 读取特征值

//读取特征值
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {if (mBluetoothAdapter == null || mBluetoothGatt == null) {Log.i(TAG, "readCharacteristic: BLE not init");return;}mBluetoothGatt.readCharacteristic(characteristic);
}

在蓝牙设备连接成功后自动读一次特征值。

3.5 写入特征值

//写入特征值
public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {if (mBluetoothAdapter == null || mBluetoothGatt == null) {Log.i(TAG, "writeCharacteristic: BLE not init");return;}mBluetoothGatt.writeCharacteristic(characteristic);
}

这是完成手机APP向蓝牙设备写数据的操作。

3.6 设置特征值变化通知
这个很重要,如果不设置话,手机APP是接收不到蓝牙设备发送的数据。

//设置特征值变化通知
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristicNotification, boolean enabled) {if (mBluetoothAdapter == null || mBluetoothGatt == null) {Log.i(TAG, "setCharacteristicNotification: BLE not init");return;}mBluetoothGatt.setCharacteristicNotification(characteristicNotification, enabled);BluetoothGattDescriptor descriptor = characteristicNotification.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));if (enabled) {descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);} else {descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);}mBluetoothGatt.writeDescriptor(descriptor);
}

这个方法同样也是在第二个界面中调用的,其中UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"HC-08蓝牙设备的监听UUID,如果蓝牙设备不是一个型号,请更改为自己所用的蓝牙设备的监听UUID

3.7 获取已连接蓝牙的所有服务

//获取已连接蓝牙的所有服务
public List<BluetoothGattService> getDupportedGattServices() {if (mBluetoothGatt == null) {return null;}return mBluetoothGatt.getServices();
}

返回已经连接蓝牙设备的所有服务。

3.8 读取蓝牙设备的RSSI值

//读取RSSI
public void readRssi() {if (mBluetoothAdapter == null || mBluetoothGatt == null) {Log.i(TAG, "readRssi: BLE not init");return;}mBluetoothGatt.readRemoteRssi();
}

该方法返回的是已连接的蓝牙设备的信号值(RSSI)。

3.9 连接外围设备的回调函数

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {@Override//重写 蓝牙连接状态public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {if (status == BluetoothGatt.GATT_SUCCESS) {String intentAction;if (newState == BluetoothProfile.STATE_CONNECTED) {intentAction = ACTION_GATT_CONNECTED;mConnectionState = STATE_CONNECTED;broadcastUpdate(intentAction);mBluetoothGatt.discoverServices();   //发现服务} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {intentAction = ACTION_GATT_DISCONNECTED;mConnectionState = STATE_DISCONNECTED;broadcastUpdate(intentAction);}}}//重写 蓝牙发现服务@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {if (status == BluetoothGatt.GATT_SUCCESS) {broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);Log.i(TAG, "onServicesDiscovered: 蓝牙发现服务");} else {Log.i(TAG, "onServicesDiscovered: 蓝牙发现服务失败" + status);}}//重写 蓝牙读特征@Overridepublic void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {if (status == BluetoothGatt.GATT_SUCCESS) {Log.i(TAG, "onCharacteristicRead: is called");byte[] sucString = characteristic.getValue();broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);}}//重写 蓝牙写特征@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {Log.i(TAG, "onCharacteristicWrite: 写数据成功");}//重写 蓝牙特征改变@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {Log.i(TAG, "onCharacteristicChanged: changed changed changed changed changed ");broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);}//重写 蓝牙读描述值@Overridepublic void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {if (status == BluetoothGatt.GATT_SUCCESS) {Log.i(TAG, "onDescriptorRead: Read Read Read");byte[] desc = descriptor.getValue();if (desc == null) {Log.i(TAG, "onDescriptorRead: desc is null null null");}}}//重写 蓝牙写描述值@Overridepublic void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {if (status == BluetoothGatt.GATT_SUCCESS) {Log.i(TAG, "onDescriptorWrite: Write Write Write");}}@Overridepublic void onReliableWriteCompleted(BluetoothGatt gatt, int status) {if (status == BluetoothGatt.GATT_SUCCESS) {Log.i(TAG, "onReliableWriteCompleted: onReliableWriteCompleted onReliableWriteCompleted onReliableWriteCompleted");}}//重写 获取蓝牙信号值@Overridepublic void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {if (status == BluetoothGatt.GATT_SUCCESS) {Log.i(TAG, "onReliableWriteCompleted: RSSI RSSI RSSI");broadcastUpdate(ACTION_DATA_AVAILABLE, rssi);}}
};

在这个回调函数中可以得到已连接的蓝牙设备的所有状态,包括:是否连接成功、是否发送数据成功以及是否读取数据成功等等,然后在这个服务中通过BroadCast(广播)将信息发出去,在第二个界面中设置广播的监听接收器,进而完成数据的传输。

3.10 发送广播

//更新广播
private void broadcastUpdate(final String action) {final Intent intent = new Intent(action);sendBroadcast(intent);
}//更新广播
private void broadcastUpdate(final String action, int rssi) {final Intent intent = new Intent(action);intent.putExtra(EXTRA_DATA, rssi);sendBroadcast(intent);
}//更新广播
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {final Intent intent = new Intent(action);final byte[] data = characteristic.getValue();//将data的数据传输给主空间中保存if (data != null && data.length > 0) {final StringBuilder stringBuilder = new StringBuilder(data.length);for (byte byteChar : data) {stringBuilder.append(String.format("%02X", byteChar));Log.i(TAG, "broadcastUpdate: byteChar is:" + byteChar);}intent.putExtra("BLE_BYTE_DATA", data);intent.putExtra(EXTRA_DATA, new String(data));}sendBroadcast(intent);}

通过广播的形式将数据发出去,在第二个界面中通过设置过滤器接收对应的广播。

3.11 获取服务的对象

当在第二个界面中成功绑定了该服务,通过调用这个方法即可返回一个该服务的对象。

public class LocalBinder extends Binder {public BlutoothBLEService getService() {return BlutoothBLEService.this;}}@Nullable
@Override
public IBinder onBind(Intent intent) {return mBinder;
}public boolean onUnbind(Intent intent) {close();return super.onUnbind(intent);
}

4.绑定服务

在完成服务的代码编写之后,接着需要在第二个界面中绑定该服务,在onCreat方法中进行绑定,代码如下:

Intent getServiceIntent = new Intent(this, BlutoothBLEService.class);
bindService(getServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

5.绑定服务的回调函数

是否成功的绑定了服务,我们可以在回调函数中获知,代码如下:

private BlutoothBLEService mBlutoothBLEService;//服务(BlutoothBLEService.class)连接 回调函数
private final ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mBlutoothBLEService = ((BlutoothBLEService.LocalBinder) service).getService();if (!mBlutoothBLEService.initialize()) {Log.i(TAG, "onServiceConnected: MainActivity BLE not init");finish();}Log.i(TAG, "onServiceConnected: 8888888888888");mBlutoothBLEService.connect(address);}@Overridepublic void onServiceDisconnected(ComponentName name) {mBlutoothBLEService = null;}
};

如果绑定成功,首先执行mBlutoothBLEService = ((BlutoothBLEService.LocalBinder) service).getService()获取这个服务的对象,然后执行mBlutoothBLEService.initialize()对服务进行初始化。

6.注册/取消注册广播

//注册广播和IntentFilter
@Override
protected void onResume() {registerReceiver(mBroadCastReceiver, makeGattUpdateIntentFilter());if (mBlutoothBLEService != null) {Log.i(TAG, "onResume: 99999999999999");boolean res = mBlutoothBLEService.connect(address);Log.i(TAG, "onResume: " + res);}super.onResume();
}//取消注册广播和IntentFilter
@Override
protected void onDestroy() {unregisterReceiver(mBroadCastReceiver);mBlutoothBLEService = null;super.onDestroy();
}

上述代码利用registerReceiver(mBroadCastReceiver, makeGattUpdateIntentFilter())unregisterReceiver(mBroadCastReceiver)方法完成注册和取消注册广播,下面的代码是设置广播接收和过滤器。

//IntentFilter 设置过滤 与广播进行注册
public IntentFilter makeGattUpdateIntentFilter() {IntentFilter filter = new IntentFilter();filter.addAction(BlutoothBLEService.ACTION_GATT_CONNECTED);filter.addAction(BlutoothBLEService.ACTION_GATT_DISCONNECTED);filter.addAction(BlutoothBLEService.ACTION_GATT_SERVICES_DISCOVERED);filter.addAction(BlutoothBLEService.ACTION_DATA_AVAILABLE);return filter;
}
//设置广播接收 服务(BlutoothBLEService.class)传过来得信息
BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String actionString = intent.getAction();if (BlutoothBLEService.ACTION_GATT_CONNECTED.equals(actionString)) {    //蓝牙设备连接成功Log.i(TAG, "onReceive: " + name + " 连接成功");status = "Connected";updateConnectionState(status);} else if (BlutoothBLEService.ACTION_GATT_DISCONNECTED.equals(actionString)) { //蓝牙设备连接失败Log.i(TAG, "onReceive: " + name + " 断开连接");status = "Disconnected";updateConnectionState(status);} else if (BlutoothBLEService.ACTION_GATT_SERVICES_DISCOVERED.equals(actionString)) {   //蓝牙设备设置服务Log.i(TAG, "onReceive: 广播接收到服务");displayGattServices(mBlutoothBLEService.getDupportedGattServices());} else if (BlutoothBLEService.ACTION_DATA_AVAILABLE.equals(actionString)) {    //蓝牙设备有数据提供Log.i(TAG, "onReceive: 有数据");displayData(intent.getExtras().getString(BlutoothBLEService.EXTRA_DATA), intent);}}
};

其中displayGattServices(mBlutoothBLEService.getDupportedGattServices())进一步完成发现服务,displayData(intent.getExtras().getString(BlutoothBLEService.EXTRA_DATA), intent)进一步完成数据接收的处理,updateConnectionState(status)是完成蓝牙状态的更新操作,这三个代码将在下文进行说明。

7.发现已连接蓝牙设备服务

public static String CHARACTERISTIC_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb";
private BluetoothGattCharacteristic target_chara;
private Handler mHandler = new Handler();//服务
public void displayGattServices(List<BluetoothGattService> gattServices) {if (gattServices == null) {return;}for (BluetoothGattService service : gattServices) {List<BluetoothGattCharacteristic> gattCharacteristics = service.getCharacteristics();for (final BluetoothGattCharacteristic characteristic : gattCharacteristics) {if (characteristic.getUuid().toString().equals(CHARACTERISTIC_UUID)) {mHandler.postDelayed(new Runnable() {@Overridepublic void run() {mBlutoothBLEService.readCharacteristic(characteristic);}}, 200);mBlutoothBLEService.setCharacteristicNotification(characteristic, true);target_chara = characteristic;}}}
}

其中CHARACTERISTIC_UUIDHC-08蓝牙设备的读写特征UUID,如果使用的蓝牙设备型号不一样请改为自己所用的蓝牙设备的读写特征UUID,根据这个UUID找到蓝牙设备的读写特征,从而设置特征变化通知和记录这个特征。

8.数据的接收

//接收的数据
public void displayData(String rev_string, Intent intent) {try {byte[] data = intent.getByteArrayExtra("BLE_BYTE_DATA");if (data == null) {Log.i(TAG, "displayData: data is empty");return;}rev_string = new String(data, 0, data.length, "GB2312");} catch (UnsupportedEncodingException e) {e.printStackTrace();}rev_str = rev_str + rev_string;runOnUiThread(new Runnable() {@Overridepublic void run() {text2.setText(rev_str);}});
}

上面的代码完成数据的接收,并将接收到的数据放入控件text2中进行追加显示。

9.更新蓝牙连接状态

private tempHandler myHandler = new tempHandler();
private String rev_str = "";//更新蓝牙连接状态
private void updateConnectionState(String Status) {Message msg = new Message();msg.what = 1;Bundle bundle = new Bundle();bundle.putString("connect_state", status);msg.setData(bundle);myHandler.sendMessage(msg);
}private class tempHandler extends Handler {@Overridepublic void handleMessage(@NonNull Message msg) {switch (msg.what) {case 1:String str;str = msg.getData().getString("connect_state");text1.setText("状态:" + str);break;}super.handleMessage(msg);}
}

在控件text1中更新显示当前蓝牙的连接状态。

10.发送数据

//发送数据线程
public class sendDataThread implements Runnable {public sendDataThread() {new Thread(this).start();}@Overridepublic void run() {if (editText.getText() != null) {byte[] buff = null;try {buff = editText.getText().toString().getBytes("GB2312");Log.i(TAG, "run: " + buff.length);} catch (UnsupportedEncodingException e) {e.printStackTrace();}int[] sendDataLens = dataSparate(buff.length);for (int i = 0; i < sendDataLens[0]; i++) {byte[] data20 = new byte[20];for (int j = 0; j < 20; j++) {data20[j] = buff[i * 20 + j];}target_chara.setValue(data20);mBlutoothBLEService.writeCharacteristic(target_chara);}if (sendDataLens[1] != 0) {byte[] lastData = new byte[sendDataLens[1]];for (int i = 0; i < sendDataLens[1]; i++) {lastData[i] = buff[sendDataLens[0] * 20 + i];}if (lastData != null) {target_chara.setValue(lastData);mBlutoothBLEService.writeCharacteristic(target_chara);} else {Log.i(TAG, "run: last是空的");}}}}
}//发送数据实现点击事件
@Override
public void onClick(View v) {new sendDataThread();
}//数据分包处理
private int[] dataSparate(int len) {int[] lens = new int[2];lens[0] = len / 20;lens[1] = len % 20;return lens;
}

通过点击发送按钮,创建一个发送数据的线程,发送的数据将进行分包处理依次发送,确保即使数据太大也能成功的发送。

至此Android的BLE蓝牙(HC-08)的配置全流程都已详细的说明,如有任何问题可以留言或者私信我,看到会及时回复,上述的内容如果有误,还请各位大佬不吝赐教,在此,祝愿各位学习顺利,前途无限~

Android BLE蓝牙(HC-08)源码免费获取方式

STM32与BLE蓝牙通信 Android APP配置(二)相关推荐

  1. 低功耗蓝牙(BLE)在 Android APP 中的应用

    低功耗蓝牙(BLE)在 Android APP 中的应用 前言 最近公司接了一个新项目,用户可以把自己的乐器跟Phone或Pad连接起来,当弹奏乐器的时候,会把演奏情况同步反馈到设备上,方便用户练习, ...

  2. React Native BLE蓝牙通信 App开发

    由于公司项目需要,开发一个基于rn的app与公司蓝牙模块下位机进行通讯.用来扫描并连接可用的外设,然后读取和写入数据. 项目选用的蓝牙库是:react-native-ble-manager,详细安装教 ...

  3. React Native BLE蓝牙通信

    由于项目需要,基于React Native 开发的App要跟BLE蓝牙设备通信. 在js.coach上搜索React Native BLE蓝牙组件,只找到三个组件: react-native-ble- ...

  4. 轻松易懂arduino低功耗BLE蓝牙通信

    今天我们介绍蓝牙通信的另一种方式--BLE(Bluetooth Low Energy,蓝牙低功耗).         什么是BLE         在<无线通信3:HC05/HC06经典蓝牙BT ...

  5. Winform BLE 蓝牙通信

    在网上找了很多资料关于Winform如何使用电脑自带蓝牙与设备(手机.仪器.工具.3C电器等等)的低功耗蓝牙(BLE)进行通信的示例,找了很久都没有一个完整的解决方案,最近终于经过自己的不断研究实现了 ...

  6. c#下BLE蓝牙通信

    工作需要,要求在原有的c#界面中添加ble蓝牙通信模块,想要嵌入到原有代码中:这里网上也是有很多实例,也是参考了许多博主的文章其实都大同小异,主要还是在环境搭建这里: 我首先新建了一个c#控制台应用, ...

  7. 【Android App】二维码的讲解及生成属于自己的二维码实战(附源码和演示 超详细必看)

    需要全部代码请点赞关注收藏后评论区留言~~~ 一.二维码基本内容介绍 条形码只能表达十几位数字编码,无法表示更复杂的数据. 二维码在二维方格上描出一个个黑点,从而表达更丰富的信息. 二维码早已在手机A ...

  8. 基于STM32的双蓝牙通信

    首先我们应该让两个蓝牙间互相通信 1.准备两个蓝牙模块(主从一体),用USB转TTL连接到电脑,再打开两个串口分别连接两个蓝牙模块,上电同时按住蓝牙上的按键进入AT指令模式(指示灯慢闪),波特率设置为 ...

  9. android ble蓝牙不稳定,Android滞后/不稳定的蓝牙连接

    我在使用不安全的RFCOMM连接连接到WML-C46 AH Bluetooth Chip时遇到问题.我用相关的代码写了一个android应用程序来向你展示我的问题.Android滞后/不稳定的蓝牙连接 ...

最新文章

  1. C++知识点46——类继承中的类型转换与访问权限控制(中)
  2. Center OS 5.5 下安装 和 配置 Tomcat 7
  3. 风变python基础语法第11关_Python基础语法学习笔记之风变第十四关项目实操
  4. controller配对与接触配对
  5. 面试题 02.02. 返回倒数第 k 个节点
  6. ApplePay支付使用
  7. OBIEE-----ClusterControler通信的问题
  8. 云计算引入可能破坏之前建立的IT秩序
  9. 两个卡巴斯基 6.0 官方简体中文版授权文件
  10. java开发利器 eclipse从入门到精通 pdf_Java从入门到精通(第4版)高清PDF下载
  11. 易语言网页填表取不到cookie_易语言置外部浏览器Cookie例子(支持所有浏览器)...
  12. 计算机 海底世界 教案,海底世界教学反思?海底世界儿童画?鱼鱼桌面海底世界...
  13. subli快速度创建html,Shortcut to comment out a block of code with subli
  14. uboot 中Nand flash 常用操作命令解析
  15. bootstrap黑色酷炫IT行业个人博客模板
  16. 传音上演另类国产手机出海记:非洲之王却闯不出非洲
  17. CSS深入理解之line-height
  18. Ubuntu云安装桌面版
  19. 使用ASP.NET.MVC制作手机接收验证码
  20. Docker数据卷挂载相关

热门文章

  1. 【布局优化】基于鲸鱼算法实现3D无线传感器网(WSN)覆盖优化 Matlab源码
  2. unity--shader graph--特效场景的建立
  3. vb计算机二级第二天比第一天难,计算机二级VB常用算法
  4. node点滴积累----http.createServer()
  5. 什么才是真正的 RESTful 架构
  6. word文档docx解密助手,word文档docx复制打印限制怎么解除?
  7. 数据结构学习笔记——图的遍历算法(深度优先搜索和广度优先搜索)
  8. 如何关闭微软Edge小冰
  9. 鬼舞者3(Onimusha 3)
  10. 安卓开发——问题:getFragmentManager().beginTransaction().add()传入v4.fragment出错