安卓异步线程消息机制学习——Handler+Thread+Looper


前言:在安卓应用开发中面临着一个问题,如果应用在主线程(即UI线程)中进行网络通信的时候很有可能会造成主线程长时间阻塞,而阻塞超过5秒钟程序就会崩溃!自然可以考虑新建一个工作线程(Thread)来完成网络通信,那么问题又来了,譬如在完成了网络通信后往往需要更新UI,我们的网络通信是在子线程中完成的,而安卓的UI交互是在主线程中实现的!显然,我们无法在网络通信的子线程中更新UI。如果说子线程可以在自己完成任务后发一个相应的消息给主线程,那么主线程就可以根据消息的内容去完成UI更新,那么Handler对象就扮演着在子线程和主线程之间发送、传递、处理消息的角色。聪明的你一定意识到了,如果主线程收到的消息比较多,它一定忙不过来,那么主线程肯定要有一个消息队列,Looper对象就是负责管理这个消息队列。(说明一点,本文并不会过多涉及代码的实现



android异步线程消息机制示意图


一、Thread

实现一个子线程,主要两种方式:1、继承Thread对象,重写run()方法;2、实现Runnable接口的run()方法生成线程体,用这个线程体实例化一个Thread对象。

注:需要注意的是Thread类实际上也是实现了Runnable接口,如果直接调用run()方法,代码实际上还是在主线程中跑。必须调用Thread对象的start()方法才会创建一个新线程,我的理解是实例化一个Thread对象只是分配给这个独立线程需要的资源,调用start()方法使得这个线程处于就绪状态!


一、MessageMessageQuenenLooper

1、Message对象,主要使用到Message.whatMessage.obj两个属性,前者是消息的唯一标识,后者是传递的消息内容。(提一下,线程之间消息的传递可以通过Handler对象实现,进程之间消息的传递是Messger对象实现,这个后面再继续学习一下)。

2、MessageQuenenLooperThread的联系


如图所示,一个线程只有一个Looper对象管理着一个消息队列,需要注意的是只有和Looper对象绑定的线程才有消息队列,我们把这样的线程称作Looper线程。主线程自然是Looper线程,但是我们实现的子线程并不是!当然通过代码可以实现子线程和Looper对象的绑定,并为它分配一个消息队列,了解一下Looper的源码实现能更好的帮助我们理解MessageQuenenLooperThread之间对应的关系。




我们就不过多去纠结代码细节问题了,重点在于调用Looper对象的prePare()方法后Looper对象会创建一个消息队列并且和当前的线程绑定。同时Looper对象的loop方法负责不断的从消息队列中取消息,交给Handler对象处理。

注:在主线程中,Looper的实现对我们来说是‘透明’的!不用去考虑代码实现Looper、消息队列、线程之间的关联,只要在主线程中实例化Handler对象,重写handleMessage()方法处理消息,子线程里面引用主线程实例化的Handler对象发送消息。


一、消息机制的实现

1、子线程向主线程发送消息

主线程接受并处理消息,自然是在主线程实例化Handler对象,这样主线程的Looper对象才能从主线程的消息队列中提取消息给Handler对象处理,而子线程中引用主线程实例化的Handler对象发送消息。

参考代码:

 

主线程中(实例化Handler对象):

    class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            //根据msg.waht识别不同消息,处理msg.obj数据
        }
    }

子线程中(线程体中引用Handler对象发送消息):

public void run() {
        try {  

        // 执行相应业务,例如网络通信
            ...........
            // 任务完成后创建通知UI线程的消息

            Message msg = handler.obtainMessage();

            msg.waht=XXX;

            msg.obg=XXX;
            // 发送消息
            handler.sendMessage(msg);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

 

    

 

2、主线程向子线程发送消息

主线程向子线程发送消息的实现逻辑和上述是类似的(反一下而已),不同的地方在于:主线程默认就是Looper线程,不需要再去代码实现线程、Looper、消息队列的关联!而子线程则必须要有这一步

 

代码参考:

 

子线程:

public class LooperThread extends Thread {
    @Override
    public void run() {
        // 将当前线程初始化为Looper线程
        Looper.prepare();

        //子线程需要处理的任务


        // 实例化handler
        
        // 开始循环处理消息队列
        Looper.loop();
    }
}

 

 

注:Handler对象除了可以发送Message对象到消息队列外,也可以通过post()方法和postDelay()方法发送Runnable线程体对象到消息队列中。通过源码的解读可以发现其实质还是发送了一个Message对象,该Message对象具有callback属性,其callback属性值即是发送的Runnable线程体。




智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告