Android蓝牙应用AsyncTask仅首次点击运行问题求助
解决Android AsyncTask蓝牙扫描重复点击失效问题
看起来你遇到的核心问题是用空循环模拟扫描时长的逻辑完全不可靠,再加上线程安全和AsyncTask与蓝牙扫描生命周期脱节的问题,导致第二次点击时任务快速结束。我来帮你一步步拆解问题并修复:
问题根源分析
- 空循环的不可靠性:你在
doInBackground()里用for (int i = 0; i < 100000000; i++) {}这种空循环模拟延迟,这完全依赖设备CPU性能——第一次点击时CPU负载低可能跑2秒,但第二次点击时CPU有缓存或负载变化,循环会瞬间跑完,根本没法稳定控制进度条时长。 - 线程安全问题:
Scan_btn_clic是全局变量,UI线程(点击事件)和后台线程(doInBackground())同时访问它却没有同步机制,很容易导致状态判断混乱。 - AsyncTask与蓝牙扫描脱节:你把扫描的启动/停止放在
onPreExecute()/onPostExecute(),但doInBackground()的循环和实际蓝牙扫描状态完全无关——蓝牙扫描时长由系统决定,不是空循环能控制的。
修复方案
1. 移除空循环,改用扫描事件驱动进度
首先通过蓝牙广播接收器跟踪扫描状态,替代空循环逻辑:
private BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 发现新设备,可在此更新设备列表 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { // 扫描结束,重置进度和按钮状态 progressBar.setProgress(100); Scan_btn.setText("Scan"); } } };
2. 重构AsyncTask,绑定蓝牙扫描生命周期
修改Maj AsyncTask,让它和蓝牙扫描真正绑定:
private class Maj extends AsyncTask<Void, Integer, Void> { private boolean isScanning = false; @Override protected void onPreExecute() { super.onPreExecute(); // 注册广播接收器 IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(bluetoothReceiver, filter); // 启动扫描 if (blueAdapter.isEnabled() && !blueAdapter.isDiscovering()) { isScanning = true; blueAdapter.startDiscovery(); Scan_btn.setText("Stop Scan"); // 定时更新进度条 new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { int progress = 0; @Override public void run() { if (isScanning && progress < 100) { progress += 5; publishProgress(progress); Handler(Looper.getMainLooper()).postDelayed(this, 200); } } }, 0); } } @Override protected Void doInBackground(Void... voids) { // 等待扫描结束,替代空循环 while (isScanning && blueAdapter.isDiscovering()) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); progressBar.setProgress(values[0]); } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); // 清理资源 if (blueAdapter.isDiscovering()) blueAdapter.cancelDiscovery(); try { unregisterReceiver(bluetoothReceiver); } catch (Exception e) {} isScanning = false; Scan_btn.setText("Scan"); progressBar.setProgress(0); } @Override protected void onCancelled() { super.onCancelled(); // 任务取消时也要清理资源 if (blueAdapter.isDiscovering()) blueAdapter.cancelDiscovery(); try { unregisterReceiver(bluetoothReceiver); } catch (Exception e) {} isScanning = false; Scan_btn.setText("Scan"); progressBar.setProgress(0); } }
3. 修复按钮点击逻辑,避免重复任务
修改点击事件,确保每次点击要么启动新任务,要么取消当前任务:
Scan_btn.setOnClickListener(new View.OnClickListener() { private Maj currentScanTask; @Override public void onClick(View view) { if (blueAdapter.isDiscovering()) { // 取消当前扫描任务 if (currentScanTask != null && !currentScanTask.isCancelled()) { currentScanTask.cancel(true); } Scan_btn_clic = false; } else { // 启动新扫描任务 if (currentScanTask != null && currentScanTask.getStatus() == AsyncTask.Status.RUNNING) { currentScanTask.cancel(true); } currentScanTask = new Maj(); currentScanTask.execute(); Scan_btn_clic = true; } } });
额外建议
- AsyncTask已被弃用:从Android 11开始,AsyncTask已被官方弃用,建议改用Kotlin Coroutines或Java ExecutorService + Handler实现后台任务,生命周期控制更灵活。
- 权限检查:确保已申请
BLUETOOTH_SCAN、BLUETOOTH_ADMIN等必要权限(Android 12+需动态申请BLUETOOTH_SCAN)。
内容的提问来源于stack exchange,提问作者HQ_BT
相关产品推荐
相关产品推荐

