Android异步消息处理之Thread+Handler

本文总结了Android异步消息处理机制,通过Thread+Handler的方式,深入探讨了内部工作原理,旨在帮助读者从应用层面升至机制理解。
摘要由CSDN通过智能技术生成

前言:之前看了网上很多关于Android异步消息处理机制的文章,对于这块知识从一般性的应用上升到了内部机制的理解,受益匪浅。本着“看过没总结过等于没收获过”的原则,也对Android异步消息处理这块做个总结,内容如有错误之处还望指正。

通过该blog可以了解到开发中为什么需要异步消息处理;怎样创建线程以及创建Handler;通过Handler和Looper的源码了解Handler与消息循环的内部沟通过程,Handler发送消息的两种方式以及如果获取消息并处理消息;最后是介绍线程造成内存泄露的情况。

Android异步消息处理概述

Android Developers中Keeping Your App Response一文中:
  • No response to an input event (such as key press or screen touch events) within 5 seconds.
  • BroadcastReceiver hasn't finished executing within 10 seconds.如果输入事件(点击或触屏)在5秒之内没有响应,BroadcastReceiver在10秒之内没有执行完毕,应用程序就会报ANR错误,用户只能选择等待或强制关闭,这种用户体验是非常差的。

    主线程(main thread/UI thread),它有一个消息队列(message queue),如果屏幕上发生了点击/触屏事件就会把它转化为一个消息(message)放到消息队列里,由looper不断地从message queue里取出消息派送给相应的handler进行处理。而如果某个消息执行时间非常耗时,就会阻碍其他消息的处理,如果该条消息在5秒之内没有得到响应的话,就会报ANR。

    避免ANR的方法是创建子线程,由子线程来完成耗时任务。例如点击某条新闻查看新闻详情这一事件,它的实现过程是用户点击了某条新闻,这个点击事件会通过网络请求去获取服务器端的手机接口数据(耗时操作),获取到的新闻详情的数据内容会显示到新闻详情页面中(更新用户界面)。由子线程完成耗时任务,再由子线程处理返回结果来更新界面,这种做法是错误的,因为应用只允许在主线程里对UI做修改,子线程没有权利对用户界面做任何修改。因此子线程处理完耗时操作,其获取到修改UI的内容需要在主线程里做处理。

    之前已经提到创建子线程处理耗时任务,那么怎样将子线程获取到的数据放到主线程中处理呢?这里就需要Handler+Message来做主线程和子线程之间的沟通。整个的异步消息处理的步骤如下:

    1. 在main thread里创建worker thread来异步执行耗时任务

    2.在main thread里创建Handler,并让worker thread持有handler的引用

    3.将worker thread执行结束后,创建Message,将获取到的数据结果存放到message中

    4.由worker thread持有的的handler引用将message发送出去

    5.main thread中的handler接受到message并处理消息,UI更新


    创建子线程

    1. 创建线程的两种方式

    一、继承(extends)Thread类(适用于单继承)
    二、实现(implements)Runnable接口(当一个类已经继承某个类,就只能用Runnable来创建线程类)

    通过run()方法来执行代码,通过调用start()方法启动线程。


    实现Runnable接口创建线程:
        /**
         * 点击按钮,创建子线程
         */
        private void excuteLongTimeOperation() {
            Thread workerThread = new Thread(new MyNewThread());
            workerThread.start();
        }
    
        class MyNewThread implements Runnable{
            @Override
            public void run() {
                //执行耗时操作
                ThreadUtil.logThreadSignature();
            }
        }


    通过继承Thread类来创建线程:
        /**
         * 点击按钮,创建子线程
         */
        private void excuteLongTimeOperation() {
            Thread workerThread = new MyNewThread();
            workerThread.start();
        }
    
        public class MyNewThread extends Thread{
            @Override
            public void run() {
                super.run();
            }
        }
    可以简化为匿名内部类,更加简洁:
     /**
         * 点击按钮,创建子线程
         */
        private void excuteLongTimeOperation() {
             new Thread(){
                @Override
                public void run() {
                    super.run();
                    //执行耗时操作
                }
            }.start();
        }
    在以下情况下可以使用匿名内部类:
    1.只用到类的一个实例
    2.类在定以后马上用到
    3.类非常小
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值