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

前言

最近项目中要加一个体温测量的外设模块 利用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

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享