解决Android Handler的handleMessage()方法内TextView.setText偶尔不执行的问题

本文详细探讨了在Android应用中使用串口通信(通过CH340转USB)获取体温数据并利用Handler更新UI时遇到的数据丢失问题。作者通过分析和实验,发现将Handler设置为静态对象可以解决数据偶尔丢失的状况,但同时也引入了内存泄漏的风险。为避免内存泄漏,作者在`onDestroy()`方法中清理Handler。此外,文章还提到了在处理串口数据时的优化策略,确保数据稳定传输和UI正确渲染。

前言

最近项目中要加一个体温测量的外设模块 利用android的串口通信 可以完美的取到测量的体温数据
获取到数据后,在用Handler发送数据到View渲染时 发现一个问题 就是数据能测量到 但是渲染到
TextView时有时无!

android串口通信CH340转USB android串口通信CH340转USB(可参考)

handleMessage

在使用Handler通信时,handleMessage()这个方法内渲染TextView数据 偶尔会丢失数据渲染
这个问题出发,寻找解决方案:

看到这样一个关于Handler+Thread的例子

class MyThread implements Runnable{
    int count = 0;
    public void run() {
        while(count <= 20){
            try {
            	//每次休眠0.5秒
                Thread.sleep(500);
            }catch (Exception e){
                e.printStackTrace();
            }
            //从消息池中获得消息,如果没有消息,创建一个消息,如果有,则取出来,由handler发送
            Message message = Message.obtain();
            message.arg1 = count;
            message.obj = "jack";
            handler.sendMessage(message);
            count++;
        }
    }

Handler类如下:

class MyHandler extends Handler{
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        int arg1 = msg.arg1;
        //接收传过来的数据
        String name = (String)msg.obj;
        //渲染TextView数据
        textView.append(name+arg1);
    }
}

TextView渲染的结果
从图中可以看到 count <= 20,count++ 一共执行21次循环
得到的结果是正确的 没有漏掉一次
1

如上述结果 是我想要的 所以按照这种实现流程我测试了代码执行
结果还是有TextView漏掉渲染的问题

将Handler设置为静态对象

在翻阅资料的时候 看到这样一个说明

不在执行的问题原因: onCreate()方法不是每次启动界面都会执行的,当界面使用finish()
后界面被保存到堆栈。
第二次启动该界面时是不会在执行onCreate()方法的,而且在这之前也没有保存该界面对象的原型。
所以在finish()后实际上handler和loop都是空的。所以不会执行。
处理方法: 1.将对象handler做为静态对象使用。

于是 重新修改代码 将handler设置为静态对象

 public static Handler handler; 

依然是在Activity的onCreate()方法中初始化Handler后渲染TextView数据

 handler = new Handler() {
            public void handleMessage(Message msg) {
                // 截取返回值中的体温数据
                currentTemp1 = (String) msg.obj;
                //拿到当前的体温 数据渲染数据到页面上显示
                setTemperatureDataRealTime(currentTemp1);
            }
        };

在读体温数据时,我的代码是这样处理的
每次休眠1秒防止数据发送过快

  private class readThread extends Thread {
        public void run() {
            byte[] buffer = new byte[4096];
            while (true) {
                try {
                    //每次读取数据 休眠1秒
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                //从消息池中获得消息,如果没有消息,创建一个消息,如果有,则取出来,由handler发送
                Message msg = Message.obtain();
                int length = MyDriverManager.driver.ReadData(buffer, 4096);
                if (length > 0) {
                    String recv = toHexString(buffer, length);
                    //以16进制输出
//					String recv = new String(buffer, 0, length);		//以字符串形式输出
                    msg.obj = recv.replace(" ", "");
                    handler.sendMessage(msg);
                }
            }
        }
    }

以上代码处理数据接收以及数据发送没有问题
但是在体温测量这个页面关闭的时候 会有个bug提醒

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method
'boolean android.os.Handler.sendMessage(android.os.Message)' on a null object reference

这是一个空指针异常 是handler造成的

代码优化后是这样的写法 对handler和msg都做了一层!=null判断

private class readThread extends Thread {
        public void run() {
            byte[] buffer = new byte[4096];
            while (true) {
                try {
                    //每次读取数据 休眠0.1秒
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                //从消息池中获得消息,如果没有消息,创建一个消息,如果有,则取出来,由handler发送
                Message msg = Message.obtain();
                int length = MyDriverManager.driver.ReadData(buffer, 4096);
                if (length > 0) {
                    String recv = toHexString(buffer, length); //以16进制输出
                    if (msg != null) {
                        if (handler != null) {
                            msg.obj = recv.replace(" ", "");
                            handler.sendMessage(msg);
                        } else {
                            Log.e(TAG, "handler ------ 没有初始化 handler = null");
                        }
                    } else {
                        ALog.e(TAG, "sendMessage ------ 需要发送Message为空");
                    }
                }
            }
        }
    }

关于内存泄漏

在体温测量这个页面 静态使用Handler对象 可能会造成内存泄漏
我的处理方法是在onDestroy()方法内把handler对象置空 并且发送空数据 停止接收

 @Override
    protected void onDestroy() {
        //结束前关闭串口
        MyDriverManager.driver.CloseDevice();
        super.onDestroy();
        EventBus.getDefault().unregister(this);
        if (handler != null) {
            handler.removeCallbacksAndMessages(null);
            handler = null;
            ALog.e(TAG, "------ 把Handler置空 防止内容泄漏");
        }
    }

1

体温测量

体温测量是一个模块 需要用到串口通信 来传输测量到的体温数据 如何处理数据就要靠自己分析
一般厂家有个文档 需要一点点摸索
2

总结

最近在项目中学习了android的串口通信 感觉收获不错
一开始在测量体温数据时 偶尔拿不到页面渲染 本想就这样算了
但是本着一追到底的精神 彻底解决这个问题后心情愉悦

今天是中国民间的传统节日七夕节 没有对象 只能对知识追求探索
加油吧 不忘初心 方得始终
flight

package com.example.studycode; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.widget.Button; import android.widget.TextView; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private TextView textView; private Button button; private Handler mainHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); textView = findViewById(R.id.textView); button = findViewById(R.id.button); mainHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0: textView.setText("00000"); Log.i(TAG, "handleMessage: "+msg.toString()); break; case 1: textView.setText("111111"); Log.i(TAG, "handleMessage: "+msg.toString()); break; default: textView.setText("default"); Log.i(TAG, "handleMessage: "+msg.toString()); break; } // 更新 UI } }; button.setOnClickListener(v -> { // 启动子线程执行任务 new Thread(() -> { Message message = mainHandler.obtainMessage(); message.what = 1; message.arg1=1; message.arg2=2; long when = message.getWhen(); mainHandler.postDelayed(() -> { Log.i(TAG, "onCreate: this is a delay msg" + (when + 5000)); textView.setText("111111"); },when + 5000); // 发送消息到主线程 // mainHandler.sendEmptyMessage(0); }).start(); }); } } Handler 怎么使用 callback 处理消息逻辑
07-30
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吕氏春秋i

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值