Android Bluetooth BLE相关开发资源汇总

Android开启蓝牙开关

转载自Android:Bluetooth 的打开和关闭

检查系统蓝牙是否开启

BluetoothManager bluetoothManager = (BluetoothManager) this.
getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
mBluetoothAdapter.isEnabled();

开启系统蓝牙方式:

静默打开:
  • 注册权限:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  • 开启方式:
mBluetoothAdapter.enable();

以上静默打开 Bluetooth 开关是调用了 BluetoothAdapter.enable() 方法,首先需要获取 BluetoothAdapter 对象,如果这个对象为 null 的话,说明当前设备不支持 Bluetooth 功能。还有以下几点需要注意:
1, 在 Nexus 5 Android 4.4.4 原生系统中,在没有任何其它管理 Bluetooth 权限的应用情况下,调用强制打开 Bluetooth 的方法,没有任何提示就直接打开 Bluetooth 了。
2,在小米手机 MI 2SC / MIUI-4.7.11 (Android 4.1.1 JRO03L) 上系统自带的 “安全中心” – “应用权限管理” – “开启蓝牙” 中,有三种设置:
允许:调用强制打开 Bluetooth 代码,没有任何提示,Bluetooth 被成功打开。
提示:会弹出提示框,提示安全警告 “ ***应用尝试开启蓝牙”,可以选择“拒绝”或“允许”,还有记住此次选择(备注:如果不记住的话,下次还会弹出同样的提示框,除非你自己去修改了应用开启蓝牙的权限)。
拒绝:调用强制打开 Bluetooth 代码,没有任何提示,Bluetooth 强制打开失败。
备注:各种手机自带的权限管理功能或者第三方权限管理应用略有不同。
3,对于 BluetoothAdapter.enable() 这个方法,API 中有以下说明 (备注:初始 API 中,如 Android 2.0 Eclair / API Level 5 中并没有这段提示)
Bluetooth should never be enabled without direct user consent. If you want to turn on Bluetooth in order to create a wireless connection, you should use the ACTION_REQUEST_ENABLE Intent, which will raise a dialog that requests user permission to turn on Bluetooth. The enable() method is provided only for applications that include a user interface for changing system settings, such as a “power manager” app.
没有直接的用户的允许绝不要开启 Bluetooth。如果你想要打开 Bluetooth 创建一个无线连接,你应当使用 ACTION_REQUEST_ENABLE Intent,这样会弹出一个提示框提示用户是否开启 Bluetooth,enable() 方法仅提供给有 UI 、更改系统设置的应用来使用,例如“电源管理”应用。
从以上官方 API 提示可以看出:不建议你调用此方法来打开 Bluetooth,至少是在没有任何用户提醒的前提下!

调用系统弹出框提示用户打开
  • 注册权限:
<uses-permission android:name="android.permission.BLUETOOTH" />
  • 开启方式:
Intent requestBluetoothOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
this.startActivityForResult(requestBluetoothOn, REQUEST_CODE_BLUETOOTH_ON);

对于以上弹出系统弹框提示用户打开 Bluetooth 的代码,有以下几点需要注意:
1,这种调用系统的弹出框提示用户打开 Bluetooth 的方式,一般不会受到系统或者第三方权限管理应用的阻止。只有当你不提示用户的情况下,可以理解为“偷偷摸摸”的打开 Bluetooth ,这个是被认为侵犯用户的知情权,系统或者第三方权限管理应用可能加以阻止:直接禁止不提示用户的情况下打开 Bluetooth,或者提示用户,又或者是让用户自己选择哪些应用可以强制开启 Bluetooth。而在 Nexus 5 / Android 4.4.4 原生系统强制打开 Bluetooth 是没有任何提示,并且可以成功打开。
2,弹出系统的提示框提醒用户打开 Bluetooth 的主要代码:
this.startActivityForResult(requestBluetoothOn, REQUEST_CODE_BLUETOOTH_ON);
注意:这个方法是需要 Activity 的对象来调用的!并且需要在 Activity 中重写 onActivityResult 方法来获取用户操作弹出提示框的结果!
3,这种弹出的系统弹框,根据系统的不同,UI 会有所不同。会导致用户app视觉不统一。

跳转到系统设置中让用户自己打开:
startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));

考虑到涉及用户隐私和用户体验,推荐以下方式开启 Bluetooth :
1,采用强制开启 Bluetooth 的方式打开 Bluetooth ,但是调用强制开启 Bluetooth 代码之前,我们自己在应用中提示用户,我们的应用需要开启 Bluetooth ,让用户自己选择是否开启 Bluetooth 。自己在应用中提示用户我们需要开启 Bluetooth 相对于弹出系统的提示框提示用户当前应用需要开启 Bluetooth 的优势在于我们可以控制提示的内容和提示的方式以及 UI。
2,假若用户选择了开启 Bluetooth,但是强制开启 Bluetooth 失败,比如系统自带的权限管理禁止你的应用开启 Bluetooth ,我们不去提示用户说当前系统禁止了应用开启 Bluetooth,让用户自己去解除禁止。这样显然用户体验很差。这种情况下,我们再去调用弹出系统提示框提醒用户打开 Bluetooth 即可。这种方式一般系统或者第三方应用不会禁止。
3,如果弹出系统提示框提醒用户打开 Bluetooth 有问题的话,最后采用提示用户自己去系统 Bluetooth 设置中打开 Bluetooth,跳转到系统的 Bluetooth 设置界面。

PS:在目前Android手机中,是不支持在飞行模式下开启蓝牙的。如果蓝牙已经开启,那么蓝牙的开关状态会随着飞行模式的状态而发生改变。

BLE广播数据解析

转载自BLE 广播数据解析

BLE中peripheral设备处于被发现状态时会发送广播包,peripheral设备通过广播被中心设备发现,广播中带有peripheral设备自身的相关信息。

广播包有两种: 广播包 (Advertising Data)和 响应包 (Scan Response),其中广播包是每个设备必须广播的,而响应包是可选的。 数据包的格式如下图所示(图片来自官方 Spec):
在这里插入图片描述
每个包都是 31 字节,数据包中分为有效数据(significant)和无效数据(non-significant)两部分。

  • 有效数据部分 :包含若干个广播数据单元,称为 AD Structure 。如图中所示,AD Structure 的组成是:第一个字节是长度值 Len ,表示接下来的 Len 个字节是数据部分。数据部分的第一个字节表示数据的类型 AD Type ,剩下的 Len - 1 个字节是真正的数据 AD data 。其中 AD type 非常关键,决定了 AD Data 的数据代表的是什么和怎么解析,这个在后面会详细讲;
  • 无效数据部分 :因为广播包的长度必须是 31 个 byte,如果有效数据部分不到 31 自己,剩下的就用 0 补全。这部分的数据是无效的,解释的时候,忽略即可。

AD type

所有的 AD type 的定义在文档 Core Specification Supplement 中。 AD Type 包括如下类型:

  • Flags: TYPE = 0x01。这个数据用来标识设备 LE 物理连接的功能。DATA 是 0 到多个字节的 Flag 值,每个 bit 上用 0 或者 1 来表示是否为 True。如果有任何一个 bit 不为 0,并且广播包是可连接的,就必须包含此数据。各 bit 的定义如下:

    • bit 0: LE 有限发现模式
    • bit 1: LE 普通发现模式
    • bit 2: 不支持 BR/EDR
    • bit 3: 对 Same Device Capable(Controller) 同时支持 BLE 和 BR/EDR
    • bit 4: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR
    • bit 5…7: 预留
  • Service UUID: 广播数据中一般都会把设备支持的 GATT Service 广播出来,用来告诉外面本设备所支持的 Service。有三种类型的 UUID:16 bit, 32bit, 128 bit。广播中,每种类型类型有有两个类别:完整和非完整的。这样就共有 6 种 AD Type。

    • 非完整的 16 bit UUID 列表: TYPE = 0x02;
    • 完整的 16 bit UUID 列表: TYPE = 0x03;
    • 非完整的 32 bit UUID 列表: TYPE = 0x04;
    • 完整的 32 bit UUID 列表: TYPE = 0x05;
    • 非完整的 128 bit UUID 列表: TYPE = 0x06;
    • 完整的 128 bit UUID 列表: TYPE = 0x07;
  • Local Name: 设备名字,DATA 是名字的字符串。 Local Name 可以是设备的全名,也可以是设备名字的缩写,其中缩写必须是全名的前面的若干字符。

    • 设备全名: TYPE = 0x08
    • 设备简称: TYPE = 0x09
  • TX Power Level: TYPE = 0x0A,表示设备发送广播包的信号强度。DATA 部分是一个字节,表示 -127 到 + 127 dBm。

  • 带外安全管理(Security Manager Out of Band):TYPE = 0x11。DATA 也是 Flag,每个 bit 表示一个功能:

    • bit 0: OOB Flag,0 表示没有 OOB 数据,1 表示有
    • bit 1: 支持 LE
    • bit 2: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR
    • bit 3: 地址类型,0 表示公开地址,1 表示随机地址
  • 外设(Slave)连接间隔范围:TYPE = 0x12。数据中定义了 Slave 最大和最小连接间隔,数据包含 4 个字节:

    • 前 2 字节:定义最小连接间隔,取值范围:0x0006 ~ 0x0C80,而 0xFFFF 表示未定义;
    • 后 2 字节:定义最大连接间隔,同上,不过需要保证最大连接间隔大于或者等于最小连接间隔。
  • 服务搜寻:外围设备可以要请中心设备提供相应的 Service。其数据定义和前面的 Service UUID 类似:

    • 16 bit UUID 列表: TYPE = 0x14
    • 32 bit UUID 列表: TYPE = 0x??
    • 128 bit UUID 列表: TYPE = 0x15
  • Service Data: Service 对应的数据。

    • 16 bit UUID Service: TYPE = 0x16, 前 2 字节是 UUID,后面是 Service 的数据;
    • 32 bit UUID Service: TYPE = 0x??, 前 4 字节是 UUID,后面是 Service 的数据;
    • 128 bit UUID Service: TYPE = 0x??, 前 16 字节是 UUID,后面是 Service 的数据;
  • 公开目标地址:TYPE = 0x17,表示希望这个广播包被指定的目标设备处理,此设备绑定了公开地址,DATA 是目标地址列表,每个地址 6 字节。

  • 随机目标地址:TYPE = 0x18,定义和前一个类似,表示希望这个广播包被指定的目标设备处理,此设备绑定了随机地址,DATA 是目标地址列表,每个地址 6 字节。

  • Appearance:TYPE = 0x19,DATA 是表示了设备的外观。

  • 厂商自定义数据: TYPE = 0xFF,厂商自定义的数据中,前两个字节表示厂商 ID,剩下的是厂商自己按照需求添加,里面的数据内容自己定义。

还有一些其他的数据,我这里就不一一列举了,有需要的可以从这个文档查阅 Core Specification Supplement 。

GATT

BLE技术是基于GATT进行通信的,GATT是一种属性传输协议,简单的讲可以认为是一种属性传输的应用层协议。它的结构非常简单:
在这里插入图片描述
你可以把他看成xml来理解:

  • 每个GATT由完成不同功能的Service组成;
  • 每个Service由不同的Characteristic组成;
  • 每个Characteristic由一个value和一个或者多个Descriptor组成;
    Service、Characteristic相当于标签(Service相当于他的类别,Characteristic相当于它的名字),而value才真正的包含数据,Descriptor是对这个value进行的说明和描述,当然我们可以从不同角度来描述和说明,因此可以有多个Descriptor.

这样子理解可能不够准确,下面我们来举一个简单的例子进行说明:

常见的小米手环是一个BLE设备,(假设)它包含三个Service,分别是提供设备信息的Service、提供步数的Service、检测心率的Service;
而设备信息的service中包含的characteristic包括厂商信息、硬件信息、版本信息等;而心率Service则包括心率characteristic等,而心率characteristic中的value则真正的包含心率的数据,而descriptor则是对该value的描述说明,比如value的单位啊,描述啊,权限啊等。

作者:小时不识月z
链接:https://www.jianshu.com/p/29a730795294
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

BluetoothAdapter类介绍

摘录自Android中蓝牙的基本使用----BluetoothAdapter类简介

由于网络上关于BluetoothAdapter的一些常用API函数都有了介绍,因此,我着重介绍一些BluetoothAdapter类疏忽的地方。

1,BluetoothAdapter STATE 状态值 , 即开关状态

int STATE_OFF                 蓝牙已经关闭
int STATE_ON                  蓝牙已经打开
int STATE_TURNING_OFF         蓝牙处于关闭过程中 ,关闭ing
int STATE_TURNING_O           蓝牙处于打开过程中 ,打开ing

2,BluetoothAdapter SCAN_MOD状态值 ,即扫描状态

首先说明,可以扫描其他设备的,当然它同时能被其他蓝牙设备扫码。

int  SCAN_MODE_CONNECTABLE               表明该蓝牙可以扫描其他蓝牙设备
int  SCAN_MODE_CONNECTABLE_DISCOVERABLE  表明该蓝牙设备同时可以扫码其他蓝牙设备,并且可以被其他蓝牙设备扫描到。
int  SCAN_MODE_NONE                      该蓝牙不能扫描以及被扫描。

3,获得蓝牙适配器实例

public static synchronized BluetoothAdapter getDefaultAdapter ()
功能:获得本设备的蓝牙适配器实例。
返回值:如果设备具备蓝牙功能,返回BluetoothAdapter 实例;否则,返回null对象。

4,扫描蓝牙设备

public boolean startDiscovery () 
功能: 扫描蓝牙设备
注意: 如果蓝牙没有开启,该方法会返回false,即不会开始扫描过程。public  boolean cancelDiscovery ()
功能: 取消扫描过程。
注意: 如果蓝牙没有开启,该方法会返回false。public boolean isDiscovering ()
功能: 是否正在处于扫描过程中。
注意: 如果蓝牙没有开启,该方法会返回false。

5,获取蓝牙相关信息

public String getName ()
功能:获取蓝牙设备Namepublic String getAddress ()
功能:获取蓝牙设备的硬件地址(MAC地址),例如:00:11:22:AA:BB:CC  public boolean setName (String name)
功能:设置蓝牙设备的Name,public Set<BluetoothDevice> getBondedDevices ()
功能:获取与本机蓝牙所有绑定的远程蓝牙信息,以BluetoothDevice类实例(稍后讲到)返回。
注意:如果蓝牙为开启,该函数会返回一个空集合 。public static boolean checkBluetoothAddress (String address)
功能: 验证蓝牙设备MAC地址是否有效。所有设备地址的英文字母必须大写,48位,形如:00:43:A8:23:10:F1 。
返回值: true 设备地址有效
false 设备地址无效public BluetoothDevice getRemoteDevice (String address)
功能:以给定的MAC地址去创建一个 BluetoothDevice 类实例(代表远程蓝牙实例)。即使该蓝牙地址不可见,也会产生一个BluetoothDevice 类实例。
返回:BluetoothDevice 类实例 。注意,如果该蓝牙设备MAC地址不能被识别,其蓝牙Name为null。
异常:如果MAC  address无效,抛出IllegalArgumentException。

Android Bluetooth Low Energy (BLE) Example

转载自Android Bluetooth Low Energy (BLE) Example

Since BLE was introduced in API 18 and cannot be used on old devices, due to change of Bluetooth specifications. I suggest you to specify the min SDK version to 18 in your app. Next add these permissions and feature tags in the manifest tag of your app manifest:

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

Since I will be printing all the data in logs, there is no need for a layout file, lets have a look at the code for using Bluetooth low energy on Android:

package com.truiton.bleexample;import android.annotation.TargetApi;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.widget.Toast;import java.util.ArrayList;
import java.util.List;@TargetApi(21)
public class MainActivity extends ActionBarActivity {private BluetoothAdapter mBluetoothAdapter;private int REQUEST_ENABLE_BT = 1;private Handler mHandler;private static final long SCAN_PERIOD = 10000;private BluetoothLeScanner mLEScanner;private ScanSettings settings;private List<ScanFilter> filters;private BluetoothGatt mGatt;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mHandler = new Handler();if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {Toast.makeText(this, "BLE Not Supported",Toast.LENGTH_SHORT).show();finish();}final BluetoothManager bluetoothManager =(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);mBluetoothAdapter = bluetoothManager.getAdapter();}@Overrideprotected void onResume() {super.onResume();if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);} else {if (Build.VERSION.SDK_INT >= 21) {mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();filters = new ArrayList<ScanFilter>();}scanLeDevice(true);}}@Overrideprotected void onPause() {super.onPause();if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {scanLeDevice(false);}}@Overrideprotected void onDestroy() {if (mGatt == null) {return;}mGatt.close();mGatt = null;super.onDestroy();}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == REQUEST_ENABLE_BT) {if (resultCode == Activity.RESULT_CANCELED) {//Bluetooth not enabled.finish();return;}}super.onActivityResult(requestCode, resultCode, data);}private void scanLeDevice(final boolean enable) {if (enable) {mHandler.postDelayed(new Runnable() {@Overridepublic void run() {if (Build.VERSION.SDK_INT < 21) {mBluetoothAdapter.stopLeScan(mLeScanCallback);} else {mLEScanner.stopScan(mScanCallback);}}}, SCAN_PERIOD);if (Build.VERSION.SDK_INT < 21) {mBluetoothAdapter.startLeScan(mLeScanCallback);} else {mLEScanner.startScan(filters, settings, mScanCallback);}} else {if (Build.VERSION.SDK_INT < 21) {mBluetoothAdapter.stopLeScan(mLeScanCallback);} else {mLEScanner.stopScan(mScanCallback);}}}private ScanCallback mScanCallback = new ScanCallback() {@Overridepublic void onScanResult(int callbackType, ScanResult result) {Log.i("callbackType", String.valueOf(callbackType));Log.i("result", result.toString());BluetoothDevice btDevice = result.getDevice();connectToDevice(btDevice);}@Overridepublic void onBatchScanResults(List<ScanResult> results) {for (ScanResult sr : results) {Log.i("ScanResult - Results", sr.toString());}}@Overridepublic void onScanFailed(int errorCode) {Log.e("Scan Failed", "Error Code: " + errorCode);}};private BluetoothAdapter.LeScanCallback mLeScanCallback =new BluetoothAdapter.LeScanCallback() {@Overridepublic void onLeScan(final BluetoothDevice device, int rssi,byte[] scanRecord) {runOnUiThread(new Runnable() {@Overridepublic void run() {Log.i("onLeScan", device.toString());connectToDevice(device);}});}};public void connectToDevice(BluetoothDevice device) {if (mGatt == null) {mGatt = device.connectGatt(this, false, gattCallback);scanLeDevice(false);// will stop after first device detection}}private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {Log.i("onConnectionStateChange", "Status: " + status);switch (newState) {case BluetoothProfile.STATE_CONNECTED:Log.i("gattCallback", "STATE_CONNECTED");gatt.discoverServices();break;case BluetoothProfile.STATE_DISCONNECTED:Log.e("gattCallback", "STATE_DISCONNECTED");break;default:Log.e("gattCallback", "STATE_OTHER");}}@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {List<BluetoothGattService> services = gatt.getServices();Log.i("onServicesDiscovered", services.toString());gatt.readCharacteristic(services.get(1).getCharacteristics().get(0));}@Overridepublic void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristiccharacteristic, int status) {Log.i("onCharacteristicRead", characteristic.toString());gatt.disconnect();}};
}
disconnect() 和close()的区别

在进行BLE开发过程中可能会遇到操作失败等情况,这个时候可能需要断开与BLE的连接或者清理相关资源.在BluetoothGatt类中有两个相关的方法 。

  • disconnect()
  • close()

那么这个两个方法有什么区别,又该如何使用呢。
disconnect()方法:如果调用了该方法之后可以调用connect()方法进行重连,这样还可以继续进行断开前的操作。

close()方法:一但调用了该方法, 如果你想再次连接,必须调用BluetoothDevice的connectGatt()方法。 因为close()方法将释放BluetootheGatt的所有资源。

需要注意的问题:
当你需要手动断开时,调用disconnect()方法,此时断开成功后会回调onConnectionStateChange方法,在这个方法中再调用close方法释放资源。
如果在disconnect后立即调用close,会导致无法回调onConnectionStateChange方法。

常见问题:

BLE连接之后onServicesDiscovered不被调用

摘录自ble连接之后onServicesDiscovered 不被调用
问题:onServicesDiscovered never called while connecting to GATT Server

Something that has been really useful for me is to wait for about 600ms after the connection has been established and then start the service discovery.

项目中出现蓝牙连接上之后,始终不进onServicesDiscovered回调,mBluetoothGatt.discoverServices()做如下延时即可

if (newState == BluetoothProfile.STATE_CONNECTED) {intentAction = ACTION_GATT_CONNECTED;broadcastUpdate(intentAction);Log.i(TAG, "Connected to GATT server.");// Attempts to discover services after successful connection.//有时候发现服务不回调,需延时 https://stackoverflow.com/questions/41434555/onservicesdiscovered-never-called-while-connecting-to-gatt-server#comment70285228_41526267try {Thread.sleep(600);Log.i(TAG, "Attempting to start service discovery:"+ mBluetoothGatt.discoverServices());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}
}

相关资源:

Android低功耗蓝牙的那点事儿

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/449965.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

__invoke,try{}catch(){},microtime(),is_callable()

<?php /*1.对象本身不能直接当函数用&#xff0c;如果被当做函数用&#xff0c;会直接回调__invoke方法* 2.验证变量的内容能否作为函数调用* 3.try{}catch(Exception $e){}catch(){}finally{}* 4.microtime()函数返回当前时间戳和微妙数* */ class httpException extends …

H.264中的I_PCM模式

H.264中的I_PCM模式 I_PCM是一种帧内编码模式&#xff0c;在该模式下&#xff0c;编码器直接传输图像的像素值&#xff0c;而不经过预测和变换。在一些特殊的情况下&#xff0c;特别是图像内容不规则或者量化参数非常低时&#xff0c;该模式比常规的操作&#xff08;帧内预测…

RxPermissions 源码解析之举一反三

[toc] RxPermissions 源码解析 简介 RxPermissions 是基于 RxJava 开发的用于帮助 在Android 6.0 中处理运行时权限检测的框架。在 Android 6.0 中增加了对危险权限的动态申请&#xff0c;而不是像 Android 6.0 之前的默认全部获取的方式。 原始动态权限的获取 如果按照以往的获…

总结Selenium WebDriver中一些鼠标和键盘事件的使用

在使用 Selenium WebDriver 做自动化测试的时候&#xff0c;会经常模拟鼠标和键盘的一些行为。比如使用鼠标单击、双击、右击、拖拽等动作&#xff1b;或者键盘输入、快捷键使用、组合键使用等模拟键盘的操作。在 WebDeriver 中&#xff0c;有一个专门的类来负责实现这些测试场…

最快浮点数取绝对值

做视频算法10多年&#xff0c;经常要算绝对值&#xff0c;整数的绝对值有快速算法&#xff0c;但浮点数的绝对值没看到有快速算法&#xff0c;经常不段发现&#xff0c;得到如下浮点数的快速算法&#xff1a; 快6倍多&#xff0c; #include <Windows.h> #include <ios…

Linux ln命令、软链接和硬链接的区别

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Linux ln命令是一个非常重要命令&#xff0c;它的功能是为某一个文件在另外一个位置建立一个同步的链接。 当我们需要在不同的目录&…

Android应用开发——文件目录

Android 存储位置及 API 一、内部存储 应用安装后都会在Android 根目录生成 /data/data/packagename&#xff0c;当前应用读取不需要读写权限 注意&#xff1a; 有些开发者可能看到过应用的根目录为 /data/user/0/packagename 的情况&#xff0c;这里解释一下&#xff0c;And…

git常用命令及冲突解决

2019独角兽企业重金招聘Python工程师标准>>> git常用命令 git config --global user.name chenhongjiang git config --global user.email 123qq.com git init 建立厂库 git status 查看状态 git add . 添加当前目录 git add a.php 添加文件…

C 语言常见问题集

从 http://c-faq-chn.sourceforge.net/ccfaq/index.html 转载过来&#xff0c;学习C的好助手。 目录1. 前言2. 声明和初始化 2.1 我如何决定使用那种整数类型&#xff1f;2.2 64 位机上的 64 位类型是什么样的&#xff1f;2.3 怎样定义和声明全局变量和函数最好&#xff1f;2.4…

【题解】quake

【题解】\(quake\) 题目大意 我们共有报酬\(f\)元&#xff0c;一条边有它的价值\(w_i\),有它的建造时间\(t_i\)。要求建一些边&#xff0c;生成一颗树。求最大的利润率。 数据范围 \(n\le 400\) \(m\le10000\) \(Solution\) 实际上\(n,m\)出到\(\le 100000\)应该也是没问题的。…

Android应用开发——service连接泄露异常:android.app.ServiceConnectionLeaked: that was originally bound here

在做service开发过程中&#xff0c;大部分可能会遇到以下异常&#xff0c;该异常仅通过log输出&#xff0c;并不会导致app crash。 E/ActivityThread: Activity com.example.image.all_samples.Main2Activity has leaked ServiceConnection com.example.image.all_samples.Mai…

Linux more命令、Linux rhmask命令

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Linux more 命令类似 cat &#xff0c;不过会以一页一页的形式显示&#xff0c;更方便使用者逐页阅读&#xff0c;而最基本的指令就是按…

从零开始学习PYTHON3讲义(二)把Python当做计算器

《从零开始PYTHON3》第二讲 上一讲我们说过了如何启动Python IDLE集成开发学习环境&#xff0c;macOS/Linux都可以在命令行执行idle3。Windows则从开始菜单中去寻找IDLE程序的图标。 上一讲我们还见到了Python的两种工作模式&#xff0c;交互模式和程序模式。 通常在一个大型的…

Tranquility

本页目录与Kafka集群交互Druid使用Tranquility Kafka本文以Kafka为例&#xff0c;介绍在E-MapReduce中如何使用Tranquility从Kafka集群采集数据&#xff0c;并实时推送至Druid集群。 Tranquility是一个以push方式向Druid实时发送数据的应用。它替用户解决了分区、多副本、服务发…

Iot相关杂烩

人工智能就像人的大脑&#xff0c;而 IoT 就像人的神经网络 1&#xff09;在天空中巨大的鸟群里&#xff0c;每一只鸟儿都实时判断自己和四周同伴的距离。这时&#xff0c;它们各自都是一个物联网节点。2&#xff09;这些“节点”并不是简单地收集数据&#xff0c;而是在实时计…

水滴石穿C语言之指针、数组和函数

基本解释   1、指针的本质是一个与地址相关的复合类型&#xff0c;它的值是数据存放的位置&#xff08;地址&#xff09;&#xff1b;数组的本质则是一系列的变量。   2、数组名对应着&#xff08;而不是指向&#xff09;一块内存&#xff0c;其地址与容量在生命期内保持…

告诉你银行在年底为存储做的小动作

25年前&#xff0c;银行的存款利率是10.98%&#xff0c;可谓巅峰时刻。15年前&#xff0c;银行的存款利率开始下降&#xff0c;降到了8%的利率。 到了5年前&#xff0c;银行的存款利率毫无回转之势&#xff0c;直线下降到了5%的利率。 而如今&#xff0c;我们无可奈何地接受了2…

爬虫学习(五)——百度贴吧的爬取

import osimport timeimport urllib.requestimport urllib.parse# 输入目标页码和吧名def header(): url "https://tieba.baidu.com/f?" baming input("请输入要爬取的吧名") start_page int(input("请输入起始页")) end_page …

什么是嵌入式设备?/ 嵌入式设备的定义

什么是嵌入式设备&#xff1f;/ 嵌入式设备的定义 区别于通用计算机的其他设备都可以称之为嵌入式设备 &#xff08;个人电脑&#xff0c;服务器&#xff09; 一段时期内&#xff0c;必备的硬件配置。 嵌入式开发包括哪些部分&#xff1a; 底层驱动开发&#xff1a; 关键字…

Linux mv命令、Linux cp命令、Linux scp命令

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Linux mv命令用来为文件或目录改名、或将文件或目录移入其它位置。 语法 mv [options] source dest mv [options] source... director…