android线程消息传递机制——Looper,Handler,Message

线程间的通信是需要几个类一起配合使用才行,这几个类分别是:

Looper,Handler,Message。其实还有一个Message Queue(MQ)的,只不过封装在Looper里面了,我们不会直接跟MQ打交道。

Looper——负责循环从MQ中取出Message,然后消息扔给Hanlder的handleMessage方法,
Handler——负责处理Looper分发过来的Message和发送消息给Looper。在实例化时要重写hanldeMessage方法,处理对应的消息。
Message——一个消息包而已,里面有一个target字段,表明这个Message是发给线程的哪个Handler的。
Message Queue——消息包组成的消息队列。

        下面说一下他们是如何配合运作的。当你的A线程需要接受从别的B线程发过来的消息时,就需要在A线程中创建一个Handler,B线程就可以往你创建的Handler发消息。然后A线程就可以收到消息了。但是需要注意的是,在创建Hanlder的时候,需要绑定一个Looper。如果在创建Handler时不指定与其绑定的Looper对象,系统默认会将当前线程的Looper绑定到该Handler上。如果你的当前线程没有创建Looper,系统就会报错。那有同学就说了,我平时在UI线程里用Handler时没有创建Looper也没有报错啊!那是因为系统默认已经帮UI线程创建Looper了。如果你创建的子线程也想拥有一个handler,那也需要帮你的子线程先创建一个Looper才行哦。下面用一段代码看看线程、Looper、handler、Message是怎么个回事吧。

<span style="font-size:18px;">class MyThread extends Thread
{
    public Handler mHandler;
    public void run()
    {
            Looper.prepare();
            mHandler = new Handler()
            {
            	@Override
            	public void handleMessage(Message msg)
            	{
            		//在这里处理消息
            	}
            }
            Looper.loop();
    }
} </span>

需要注意的是,一个Thread只能有一个Looper对象。如果你硬是要为一个Thread创建两个Looper,那。。。那。。。那其实你办不到!因为Looper对象定义为ThreadLocal(如果你不理解ThreadLocal,可以上网查)。保证一个Thread最多只能有一个Looper。其实Looper是不能用new去实例化的,因为Looper的构造函数是private的,调用Loop.prepare()就创建Looper了,无论你调用多少次Looper.prepare,都是一个Looper对象,有点像单例模式。而每个Thread可以拥有多个Handler。创建Hanlder时,如果没指定Looper,那么在Handler的构造函数里会关联当前线程的Looper。那他们是怎么关联的?上面代码没有见他们有关联的行为啊。其实玄机就在Handler的构造函数里。

<span style="font-size:18px;">public class handler {

    final MessageQueue mQueue;  // 关联的MQ
    final Looper mLooper;  // 关联的looper
    final Callback mCallback; 
    // 其他属性

    public Handler() {
        // 这里有一堆代码直接略过,,,
        
        // 用mLooper获取当前线程的looper
        mLooper = Looper.myLooper();
        // looper不能为空,如果为空,就是该线程没有Looper,直接报错!即该默认的构造方法只能在looper线程中使用
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        // 重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上
        mQueue = mLooper.mQueue;
        mCallback = null;
    }
    
    // 其他方法
}</span>

其实Looper里面的Loop()方法是个死循环,不断的从MQ里取消息,然后分发给对应的handler处理的。
到了这里,大家应该对这个线程的消息传递机制有一定的理解了吧?如果不理解也没关系,进代码零件官方群里讨论吧。
     看到这里,感觉线程与Handler已经很完美啦,我要下载一个东西,就先创建一个线程,下载完了就通知UI更新,一个都很美好。其实不然,假如你要下载100张图片,你不可能开100多个线程去下载吧。这样的话系统资源估计撑不住,特别是低端的手机。那怎么办。正确的办法是使用一个线程池,但是自己维护一个线程池十分的麻烦。然后Android早已经帮我们想好这一点了,我们直接使用AsyncTask类即可!其实AsyncTask内部已经维护了一个线程池,有兴趣的同学可以阅读源码。这里就不做更多的讨论了。
 最后再来梳理下多线程处理的步骤;


你可能感兴趣的:(线程,通信,handler,message,looper)