Android执行蓝牙操作时如何正常显示进度对话框及更新按钮UI
问题原因
你当前所有代码都运行在Android主线程(UI线程)中,progress.show()、设置按钮背景、启动动画这类UI操作只是把更新请求塞进了主线程的消息队列,需要等当前onClick方法完全执行完成后才会被系统处理。而你把蓝牙连接、数据流读取这类最长耗时10秒的操作直接写在了onClick里,直接阻塞了主线程,所以所有UI更新都会等到蓝牙逻辑跑完才会生效。
解决方案
核心逻辑是蓝牙耗时操作放到子线程执行,所有UI更新切回主线程操作,修改后的代码示例如下:
brefresh.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 1. 先执行所有前置UI更新,此时会立刻生效 Animation rotate_brefresh = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.rotate_clockwise); brefresh.startAnimation(rotate_brefresh); brefresh.setBackgroundResource(R.drawable.brefresh_red); progress = new ProgressDialog(MainActivity.this); progress.setTitle("Récolte des informations"); progress.setMessage("Cela prend quelques secondes"); progress.setCancelable(false); progress.show(); // 2. 新开子线程执行蓝牙耗时操作 new Thread(new Runnable() { @Override public void run() { BluetoothSocket btSocket = null; final String[] sArr = {"" ,""}; try { btSocket = hc05.createRfcommSocketToServiceRecord(mUUID); btSocket.connect(); InputStream inputStream = btSocket.getInputStream(); inputStream.skip(inputStream.available()); byte b; do { b = (byte) inputStream.read(); sArr[0] = sArr[0] + (char) b; } while (b != 94); // 94对应字符^ do { b = (byte) inputStream.read(); sArr[1] = sArr[1] + (char) b; } while (b != 59); // 59对应字符; sArr[0] = sArr[0].replace("^", ""); sArr[1] = sArr[1].replace(";", ""); } catch (IOException e) { e.printStackTrace(); } finally { // 确保蓝牙连接被关闭 if (btSocket != null) { try { btSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } // 3. 切回主线程更新UI、关闭进度提示 runOnUiThread(new Runnable() { @Override public void run() { tvpH.setText("- pH de : " + sArr[0]); tvHumidity.setText("- Humidité relative de : " + sArr[1]); progress.dismiss(); brefresh.clearAnimation(); brefresh.setBackgroundResource(R.drawable.brefresh); } }); } }).start(); } });
注意事项
- 不要在子线程中直接操作控件(比如修改文本、改按钮背景等),所有UI相关操作必须放到主线程执行,示例中用
Activity.runOnUiThread()实现线程切换。 - 蓝牙连接、IO流读写都是阻塞操作,绝对不能放到主线程执行,不仅会阻塞UI渲染,超时还会触发ANR(应用无响应)错误。
- 可以额外添加异常兜底逻辑,比如蓝牙连接失败时,切回主线程给用户弹出错误提示,同时恢复按钮状态。
内容的提问来源于stack exchange,提问作者Romain
相关产品推荐
相关产品推荐

