Android 使用线程和处理程序扫描蓝牙时出现内存问题
Android memory issue when scanning bluetooth with thread and handler
我正在使用线程和处理程序通过 BluetoothLeScanner(实际上是从 BluetoothAdapter 迁移而来)实现特定扫描周期和频率(扫描 1s、睡眠 1s、扫描 1s 等)的蓝牙扫描服务。然而,随着时间的推移,我意识到它正在消耗内存。
然后我尝试使用探查器查看发生了什么,我发现有一些递归循环。我检查了我的代码,但找不到问题所在。任何人都可以 help/encountered 同样的问题?
public class BleDetectionService extends Service {
private static Handler handler;
private static final long SCAN_PERIOD = 1100;
...
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
....
startBLEScanning();
return super.onStartCommand(intent, flags, startId);
}
private void startBLEScanning() {
mLeDeviceAdapter = new LeDeviceAdapter();
mScanning = true;
Toast.makeText(this, "BLE Service sucessfully started", Toast.LENGTH_SHORT).show();
bleScanningThread = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
while (mScanning) {
scanLeDevice(true);
}
}
}, "BLE Scanning Thread");
bleScanningThread.start();
}
private void scanLeDevice(final boolean enable) {
if (enable) {
handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
bluetoothLeScanner.stopScan(scanCallback);
}
}, SCAN_PERIOD);
// filter
ScanFilter.Builder builder = new ScanFilter.Builder();
ScanFilter filter = builder.build();
ArrayList<ScanFilter> filters = new ArrayList<>();
filters.add(filter);
// scansetting
ScanSettings.Builder settingsBuilder = new ScanSettings.Builder();
settingsBuilder.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
settingsBuilder.setReportDelay(0);
ScanSettings settings = settingsBuilder.build();
bluetoothLeScanner.startScan(filters, settings, scanCallback);
} else {
bluetoothLeScanner.stopScan(scanCallback);
}
}
}
早前记录
稍后记录
编辑:
我已经删除了线程和处理程序,因为我混淆了 BluetoothLeScanner 和 BluetoothAdapter 的使用。按照 @greeble31
的建议,现在从主线程调用 scanLeDevice()
考虑以下几点:
scanLeDevice()
在永无止境的循环中被调用,并且始终带有参数 true
。
scanLeDevice()
return 几乎立即(1 毫秒或更短)。
每次调用 scanLeDevice()
都会创建一个新的 Handler
和一个新的匿名 Runnable
。 Runnable
到 Handler
的绑定涉及 Message
(每次调用 postDelayed()
)。
您在 post 中省略了 SCAN_PERIOD
的定义,但我将进行有根据的猜测,并说它是 60000
(1 分钟)。这意味着每个新的 Handler
必须存在 1 分钟,因为它需要保持 Message
1 分钟,因为它正在跟踪 Runnable
,该 Runnable
需要在该分钟到期时执行。
换句话说:您每秒调用 scanLeDevice()
大约 1000 次,每次调用都会创建 3 个必须存在至少 1 分钟的相互关联的对象。
您的架构错误可能包括 bleScanningThread
。 scanLeDevice()
可以在主线程上安全调用。它只需要被调用一次。它将立即 return,但扫描仍将在后台进行(由 OS)。 ScanCallback
将在适当的时候执行,即使您没有提供额外的线程。当您的 postDelayed()
Runnable
执行时,扫描将停止;这可能是您一开始的意图。
我正在使用线程和处理程序通过 BluetoothLeScanner(实际上是从 BluetoothAdapter 迁移而来)实现特定扫描周期和频率(扫描 1s、睡眠 1s、扫描 1s 等)的蓝牙扫描服务。然而,随着时间的推移,我意识到它正在消耗内存。
然后我尝试使用探查器查看发生了什么,我发现有一些递归循环。我检查了我的代码,但找不到问题所在。任何人都可以 help/encountered 同样的问题?
public class BleDetectionService extends Service {
private static Handler handler;
private static final long SCAN_PERIOD = 1100;
...
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
....
startBLEScanning();
return super.onStartCommand(intent, flags, startId);
}
private void startBLEScanning() {
mLeDeviceAdapter = new LeDeviceAdapter();
mScanning = true;
Toast.makeText(this, "BLE Service sucessfully started", Toast.LENGTH_SHORT).show();
bleScanningThread = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
while (mScanning) {
scanLeDevice(true);
}
}
}, "BLE Scanning Thread");
bleScanningThread.start();
}
private void scanLeDevice(final boolean enable) {
if (enable) {
handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
bluetoothLeScanner.stopScan(scanCallback);
}
}, SCAN_PERIOD);
// filter
ScanFilter.Builder builder = new ScanFilter.Builder();
ScanFilter filter = builder.build();
ArrayList<ScanFilter> filters = new ArrayList<>();
filters.add(filter);
// scansetting
ScanSettings.Builder settingsBuilder = new ScanSettings.Builder();
settingsBuilder.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
settingsBuilder.setReportDelay(0);
ScanSettings settings = settingsBuilder.build();
bluetoothLeScanner.startScan(filters, settings, scanCallback);
} else {
bluetoothLeScanner.stopScan(scanCallback);
}
}
}
编辑: 我已经删除了线程和处理程序,因为我混淆了 BluetoothLeScanner 和 BluetoothAdapter 的使用。按照 @greeble31
的建议,现在从主线程调用 scanLeDevice()考虑以下几点:
scanLeDevice()
在永无止境的循环中被调用,并且始终带有参数 true
。
scanLeDevice()
return 几乎立即(1 毫秒或更短)。
每次调用 scanLeDevice()
都会创建一个新的 Handler
和一个新的匿名 Runnable
。 Runnable
到 Handler
的绑定涉及 Message
(每次调用 postDelayed()
)。
您在 post 中省略了 SCAN_PERIOD
的定义,但我将进行有根据的猜测,并说它是 60000
(1 分钟)。这意味着每个新的 Handler
必须存在 1 分钟,因为它需要保持 Message
1 分钟,因为它正在跟踪 Runnable
,该 Runnable
需要在该分钟到期时执行。
换句话说:您每秒调用 scanLeDevice()
大约 1000 次,每次调用都会创建 3 个必须存在至少 1 分钟的相互关联的对象。
您的架构错误可能包括 bleScanningThread
。 scanLeDevice()
可以在主线程上安全调用。它只需要被调用一次。它将立即 return,但扫描仍将在后台进行(由 OS)。 ScanCallback
将在适当的时候执行,即使您没有提供额外的线程。当您的 postDelayed()
Runnable
执行时,扫描将停止;这可能是您一开始的意图。