You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 00:00:00