【笔记】Android handler 消息处理机制

1.Looper类

looper是线程的消息循环处理器,每个线程只能有一个Looper对象,其内部有一个MessageQueue,所有消息都存放在这个队列中。

新创建一个线程时,系统不会为这个线程创建Looper,需要自己创建。Android在启动时,为主线程(UI 线程)创建一个looper 对象。

1.1 HandlerThread

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
 
    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    protected void onLooperPrepared() {
    }
 
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();//Looper类的实例必须通过prepare函数创建
        synchronized (this) {
            mLooper = Looper.myLooper();//通过myLooper方法获取Looper对象
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();//loop函数主要分发消息队列中的消息。
        mTid = -1;
    }
    
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
 
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
 
}

下面我们主要看下Looper类中的loop方法:

public static void loop() {
        final Looper me = myLooper();
... ...
        final MessageQueue queue = me.mQueue;//消息队列
 
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
 
        for (;;) {//无线循环
            Message msg = queue.next(); // might block

... ...
            msg.target.dispatchMessage(msg);//分发消息
 
... ...
 
            msg.recycle();
        }
    }

looper.loop() 就是在一个死循环中持续读取MessageQueue 中的消息并dispatch。

Handler类

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
... ...

        mLooper = Looper.myLooper();
... ...
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Handler主要负责消息的发送和处理。在一个线程中可以只用一个Hander对象处理所以消息,也可以使用多个。

1.构造一个Handler对象,需要两个参数,线程的Looper对象和消息处理函数,如果不指定looper,会使用当前线程的looper对象。
2.handler 对象创建时,调用的是当前线程的Looper对象作为mLooper,同时调用mQueue = mLooper.mQueue , 即当前线程的消息队列作为自己将要处理的消息队列(Handler.mQueue)。

3.并不是每个线程都默认有looper 对象,所以在创建handler对象之前,会先调用Looper.prepare(),为当前Thread 创建一个looper 对象

Handler.sendMessage ->Handler.sendEmptyMessage ->... ->Handler.enqueueMessage


    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//注意msg.target都是handler,因此在消息线程的loop函数处理消息时,msg.target.dispatchMessage会回到handler。
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
}

所有的发送消息接口,最后都会调用MessageQueue类中enqueueMessage函数,参数除了消息外,就是一个时间。而MessageQueue类中enqueueMessage函数只是把消息插入到消息队列中的合适位置。

总结一下:

0. 一个线程有且仅有一个looper对象,looper对象中有一个MessageQueue 作为消息队列;

1.消息机制需要一个线程环境,里面需要一个Looper对象,并且在线程的run函数中调用Looper.loop()函数;

2.函数需要一个handler来发送和处理消息。Hander要有一个Looper对象,来指定其线程,还要实现handleMessage函数。


Looper线程首先是一个Thread,由Java 标准线程变化过来:

一般的:

class LooperThread extends Thread {    //继承Thread 类
    public Handler mHandler;           //需要一个handler对象发送处理消息
    public vold run {                  //实现run() 方法
 
        Looper.prepare();              //Looper线程准备阶段
        mHandler = new Handler() {     //初始化消息处理器

            public vold handleMessage (Message msg) {
               //TODO :处理消息
            }
       
        };
        Looper.loop();                 //Looper线程循环阶段
    }


}

 以上代码可知,Looper线程实际上继承了Thread 类,并实现run 方法,运行run()时:

1.调用Looper.prepare为当前thread 创建一个Looper对象(一个线程有且仅有一个looper 对象);

2.创建handler对象,将之前创建的looper 对象的MsgQueue作为自己的MsgQueue ,负责分发和处理消息;

3.调用Looper.loop()方法进入Looper线程循环阶段;

4.handler 发送消息最后调用MessageQueue类中enqueueMessage函数,就是把消息插入到消息队列中的合适位置

猜你喜欢

转载自blog.csdn.net/pirionFordring/article/details/84139647