안드로이드에서 Bluetooth LE (Low Energy)를 사용할 때 가장 기본적인 샘플 예제 코드로 https://github.com/googlesamples/android-BluetoothLeGatt 를 많이 사용한다.
하지만 API level 21부터는 API가 약간 바뀌어 LE 디바이스를 스캔할 때 사용하는 BluetoothAdapter 클래스의 startLeScan(), stopLeScan() 메소드가 deprecated 되어 빌드해 실행하는데 문제는 없어도 android studio에서 소스를 보면 mBluetoothAdapter.
API level 21부터는 BluetoothAdapter 클래스에서 스캔을 하지 않고 BluetoothLeScanner라는 클래스가 추가되어 이 클래스의 startScan(), stopScan() 메소드를 사용해 BLE 디바이스를 검색하도록 변하였다.
콜백 역시 Bluetooth.LeScanCallback 대신 ScanCallback 클래스를 사용해야 한다.
그러므로 android-BluetoothLeGatt 예제를 API level 21의 변화에 맞게 수정하려면 다음과 같다.
먼저 사용할 클래스 import를 추가한다. DeviceScanActivity.java 소스코드 위쪽의 import 부분에 아래 내용을 추가한다.
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import java.util.List;
다음 DeviceScanActivity 클래스의 private 멤버 선언부에 밑줄 친 빨간색 내용을 추가한다.
public class DeviceScanActivity extends ListActivity {
private LeDeviceListAdapter mLeDeviceListAdapter;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
private BluetoothLeScanner mBLEScanner;
다음 onCreate 메소드의 맨 뒤쪽 부분에 다음 줄을 추가해 BluetoothLeScanner 클래스의 인스턴스를 얻는다.
if (mBluetoothAdapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
// Checks if Bluetooth LE Scanner is available. if (mBLEScanner == null) {
Toast.makeText(this, "Can not find BLE Scanner", Toast.LENGTH_SHORT).show();
finish();
return;
}
}
다음은 onListItemClick() 메소드와 scanLeDevice() 메소드 안에 있는 빨간색 줄이 쳐져 있는 startLeScan(), stopLeScan() 부분을 각각 다음 내용으로 바꿔준다.
mBLEScanner.startScan(mScanCallback); // mBluetoothAdapter.startLeScan() 부분
mBLEScanner.stopScan(mScanCallback); // mBluetoothAdapter.stopLeScan() 부분
그리고 기존의 콜백 정의부분은 없애고 다음의 내용을 추가한다.
즉 아래 부분은 통채로 삭제
// 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(); } }); }};
위쪽 내용을 삭제한 부분에 아래 내용을 추가 private ScanCallback mScanCallback = new ScanCallback() {
@Override public void onScanResult(int callbackType, ScanResult result) {
processResult(result);
}
@Override public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult result : results) {
processResult(result);
}
}
@Override public void onScanFailed(int errorCode) {
}
private void processResult(final ScanResult result) {
runOnUiThread(new Runnable() {
@Override public void run() {
mLeDeviceListAdapter.addDevice(result.getDevice());
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};