Android Handler 原理-Handler

Handler允许发送和处理与线程的MessageQueue相关联Message和Runnable对象。每一个Handler实例都与一个单独的线程和该线程的消息队列相关联。当创建Handler的时候,它被它创建的线程绑定。它把Message或Runnable对象传递到消息队列,出队的时候执行它们。Handler有两个主要用处:1.调度消息和Runnable在未来的某个时间点执行。2.入队一个操作并在不同的线程上执行。

调度消息通过post,postAtTime(Runnable,long),postDelayed,sendEmptyMessage,sendMessage,sendMessageAtTime,sendMessageDelayed方法完成。post版本允许入队Runnable对象,sendMessage版本允许入队Message对象,Message对象包含的数据会被Handler的handleMessage方法处理(需要自己实现Handler的子类)。

post或send的时候可以允许item在消息队列准备好的时候立即处理,或者定义一个时间延迟或确切的时间处理。

当一个应用的进程创建完,它的主线程专注运行一个消息队列,负责管理高级别的应用对象(Activity,BroadcastReceiver等)和他们创建的window,我们可以创建自己的子线程,并通过Handler和主线程通信。这样是通过在子线程里调用post或sendMessage方法完成。然后Runnable或Message将在Handler的消息队列里调度,在合适的时候处理。

构造函数

Handler总共有7个构造函数

#无参构造函数,内部调用6,callback传null,async传false
1. public Handler() {
        this(null, false);
    }
#设置消息处理回调,内部调用6,async传false
2. public Handler(@Nullable Callback callback) {
        this(callback, false);
    }
  #设置Looper,这样就不用调用Looper.prepare方法,内部调用7
3. public Handler(@NonNull Looper looper) {
        this(looper, null, false);
    }
    #设置Looper和回调,内部调用7
4. public Handler(@NonNull Looper looper, @Nullable Callback callback) {
        this(looper, callback, false);
    }
    #设置消息是否异步,内部调用6
5. public Handler(boolean async) {
        this(null, async);
    }
    #设置回调和是否异步,内部检测looper是否为空,所以所有内部调用这个方法的构造函数都需要先调用Looper.prepare方法初始化Looper和MessageQueue
6. public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
 #设置Looper,回调,是否异步   
7. public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Handler总共有7个构造函数,分别应用在不同场景下,可以设置消息是否异步,设置Looper,回调。

消息处理

消息处理使用dispatchMessage方法,在Looper的loop中,获取到Message以后,通过msg.target.dispatchMessage调用,msg.target是Handler实例。

 private static void handleCallback(Message message) {
        message.callback.run();
    }
        public void handleMessage(@NonNull Message msg) {
    }
    
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) { //优先处理Message的callback
            handleCallback(msg);
        } else {
            if (mCallback != null) {  //其次处理Handler的Callback对象
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //msg.callback和Handler的Callback对象都是空的,走Handler的handleMessage方法
            handleMessage(msg);
        }
    }

从上面可以看出消息处理的优先级是msg.callback>Handler的mCallback>Handler的handleMessage方法。msg.callback可以在构造Message的时候设置,mCallback可以在上述构造函数中2,4,6,7中设置,handleMessage方法可以在我们继承Handler的时候重写该方法。

发送消息

文章开头讲过,发送消息主要有两个版本,post和send。post版本会传递一个Runnable对象,封装成Message的callback,然后加入消息队列,这样post版本会在dispatchMessage的时候,优先执行msg.callback。send版本会直接传递一个Message对象。

不论是post版本还是send版本,都会调用Handler的sendMesssageAtTime方法:

 public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

然后再调用Handler的enqueueMessage方法

 private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

最终调用MessageQueue的enqueueMessage方法,把消息插入到消息队列。

移除消息


Handler移除消息的方法主要有三种removeCallback,removeMessagesremoveCallbackAndMessages

removeCallback有两个方法,内部都调用了MessageQueue的removeMessages(Handler h, Runnable r, Object object)方法:

 #移除消息队列里post的Runnbale对象是r的Message
   public final void removeCallbacks(@NonNull Runnable r) {
        mQueue.removeMessages(this, r, null);
    }
    #移除消息队列里post的Runnable对象是r且obj是token的Message,如果token是null,则移除Runnable对象是r的Message
     public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
        mQueue.removeMessages(this, r, token);
    }
    #MessageQueue的方法
      void removeMessages(Handler h, Runnable r, Object object) {
        if (h == null || r == null) { 
            return;
        }
        synchronized (this) {
            Message p = mMessages;
            // Remove all messages at front.
            #从队首Message开始查找Message的target是h,且callback是r,且object是空或obj等于object的Message对象,
            找到了就移除并回收该Message,p指向下一个节点
            while (p != null && p.target == h && p.callback == r
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            #经过上面的循环,如果p不是空,则获取p的下个节点,依然做上述条件查找Message对象,找到了就回收该Message,p的下个节点指向回收对象的下个节点,并继续查找,如果找不到则p指向下个节点,继续循环查找,直到p是null
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.callback == r
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

removeMessages方法有两个,内部调用了MessageQueue的removeMessages(Handler h, int what, Object object) 方法

 #移除消息队列里Message.what是what的消息
   public final void removeMessages(int what) {
        mQueue.removeMessages(this, what, null);
    }
    #移除消息队列里Message.what,Message.obj是object的消息,如果object是null,则移除消息队列Message.what是what的消息
 public final void removeMessages(int what, @Nullable Object object) {
        mQueue.removeMessages(this, what, object);
    }
      void removeMessages(Handler h, int what, Object object) {
        if (h == null) {
            return;
        }
        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
             #从队首Message开始查找Message的target是h,且what是what,且object是空或obj等于object的Message对象,
            找到了就移除并回收该Message,p指向下一个节点
            while (p != null && p.target == h && p.what == what
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
             #经过上面的循环,如果p不是空,则获取p的下个节点,依然做上述条件查找Message对象,找到了就回收该Message,p的下个节点指向回收对象的下个节点,并继续查找,如果找不到则p指向下个节点,继续循环查找,直到p是null
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.what == what
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

主线程的Handler

主线程Handler是在ActivityThread的main方法里获取的:

public static void main(String[] args){
   .....
   Looper.prepareMainLooper();
   ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
       }
   .....
     Looper.loop();
}

main方法里先调用Looper.prepareMainLooper方法,再实例化一个ActivityThread,再通过getHandler方法给主线程Handler赋值,再调用Looper.loop方式开启主线程的消息循环。

getHandler方法获取了AcitivityThread的mH字段

 final H mH = new H(); 
 final Handler getHandler() {
       return mH;
    }

H类是ActivityThread的内部类,主要用来处理系统消息比如应用的绑定和退出,Activity打开和生命周期,Service的创建停止等。


HandlerThread

主线程的Handler创建的时候,ActivityThread的main方法里自动帮我们调用了Looper.prepareMainLooper和Looper.loop方法,而我们在子线程创建Handler的时候,首先要调用Looper .prepare方法创建looper对象和MessageQueue对象,再创建Handler对象,再调用Looper.loop开启消息循环,否则Hanlder实例化的时候会直接抛出异常。

HandlerThread继承自Thread,内部持有Looper和Handler实例,在run方法里自动调用Looper.prepare方法和Looper.loop方法自动准备好消息队列和循环,使用HanlderThread能够简化在子线程创建Hanlder。免去调用Looper.prepare和Looper.loop方法。


总结

Handler机制是安卓消息循环机制的基石,Handler是Handler机制的指挥者

Handler发送消息方式有两个版本,post和send,post版本发送一个runnable对象,send直接发送Message对象,post和send最终都调用了MessageQueue的enqueueMessage方法。

Handler处理消息的方法是dispatchMessge方法,优先处理msg.callback,其次是Handler的mCallback对象,最后才是handleMessage方法。

Handler移除消息的方法最终都是调用MessageQueue的移除方法。

HandlerThread继承自Thread,简化了在子线程创建Handler的过程,run方法自动调用Looper.prepare和Looper.loop。


Adam博客
请先登录后发表评论
  • 最新评论
  • 总共0条评论
  • Powered by bjyblog modified by Adam © 2014-2021 www.lixiaopeng.com 版权所有 ICP证:鲁ICP备15039297号
  • 联系邮箱:14846869@qq.com