美文网首页Android知识Android开发Android技术知识
Android中的Handler机制介绍以及分析

Android中的Handler机制介绍以及分析

作者: evil_ice | 来源:发表于2017-02-09 19:53 被阅读476次

    Android中Handler机制介绍以及分析分为下面几个部分阐述

    • Handler的介绍和作用
    • Handler的使用场景示例
    • Handler机制源码分析
    • HandlerThread使用和分析
    • Handler总结
    • 一些疑问和异常

    ok,现在进入正题

    一,Handler的介绍和作用

    关于Handler的介绍我们首先从安卓官网查阅

    屏幕快照 2017-02-09 15.27.34.png

    上面大致的意思如下:

    • Handler可以发送和处理Message和Runnable对象到关联的线程的MessageQueue.每一个Handler实例关联到一个唯一的线程和这个线程的MessageQueue.当我们创建一个新的Handler时他将绑定创建它的线程以及这个线程的消息队列.

    • Handler两个主要的用途

      • 安排Message和Runnable在合适的时间被执行
      • 入队一个Action在其他线程中执行.
    • send Message和post Runnable的方法

      • post版本
        post(Runnable),
        postAtTime(Runnable, long),
        postDelayed(Runnable,long)
        对于Post版本的方法,将Runnable对象入队到MessageQueue被调用,最终是Message中执行
      • send版本
        sendEmptyMessage(int),
        sendMessage(Message),
        sendMessageAtTime(Message,long), sendMessageDelayed(Message,long)
        对于Send版本的方法,将Message对象入队后,然后被Handler的handleMessage(Message)方法处理
    • 当应用(App)的进程被创建后, 主线程默认的就会创建并运行一个与之相关联的消息队列,用来管理顶级的应用对象(activities, broadcast receivers等)以及窗口的创建.

    • 可以在创建的线程中创建新的消息队列,通过Handler可以和主线程进行交互,使用到上面的Post版本和Send版本的方法

    二,Handler使用示例

    1,子线程和主线程交互

    对于子线程和主线程通过Handler交互, 可以是子线程向主线程发送消息(例如,更新UI),也可以主线程向子线程发送消息(例如,完成某个特定的操作)

    下面代码说明

    private Handler mMainHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                System.out.println("主线程"+Thread.currentThread().getName()+"    Handler    收到消息:"+msg.obj);
                Message message = Message.obtain();
                message.obj = "消息是从主线程中发出的";
                mSubHandler.sendMessage(message);
            }
        };
    
        private Handler mSubHandler;
    
    
        private void test(){
            new Thread(){
                @Override
                public void run() {
                    super.run();
    
                    Looper.prepare();
                    mSubHandler = new Handler(){
                        @Override
                        public void handleMessage(Message msg) {
                            super.handleMessage(msg);
                            System.out.println("子线程"+Thread.currentThread().getName()+"   Handler    收到消息:"+msg.obj);
                            Message message = Message.obtain();
                            message.obj = "消息是从子线程中发出的";
                            mMainHandler.sendMessage(message);
                            //子线程Looper不在使用时退出,主线程的不能退出,否则throw new IllegalStateException("Main thread not allowed to quit.");
                            mSubHandler.getLooper().quitSafely();
                        }
                    };
                    Looper.loop();
                }
            }.start();
    
    
            Message msg = new Message();
            msg.obj = "开始发送消息";
            mMainHandler.sendMessage(msg);
    
    
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
           test();
        }
    
    2,子线程Post一个Action

    对于Post版本的方法,最终处理是在MessageQueue中的Message,所以handleMessage接收不到

    private Handler mMainHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //对于Post版本的方法,最终处理是在MessageQueue中的Message,所以在这里是接收不到的
            }
        };
    
        private void test(){
            new Thread(){
                @Override
                public void run() {
                    super.run();
    
                    mMainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println("Post一个Action");
                        }
                    });
                }
            }.start();
    
    
    
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            test();
        }
    

    三,Handler机制源码分析

    Handler机制与之相关的类 ,有Handler,Looper,Message, MessageQueue

    下面的分析以我们使用一个Handler发送一个消息或者Action的方法调用顺序开始
    当我们在一个线程中创建Handler且关联Looper消息队列需要
    Looper中的prepare()方法用来初始化当前线程Looper,然后创建Handler关联他,然后调用Looper的loop()方法

    Looper.prepare();
    Handler subHandler = new Handler();
    Looper.loop();
    
    1,Looper中的prepare()方法
     public static void prepare() {
            prepare(true);
     }
    
    2,调用重载的prepare(boolean)方法

    这个方法new一个Looper然后与当前线程关联,然后将其存放到ThreadLocal中

    private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
    3, 然后看下Looper对象在创建的时候都做了什么
     private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
    

    很简单,Looper在创建时创建一个消息队列,也就是Looper与之唯一对应

    4,Handler发送消息或者post Runnable
    • 发送消息
    public final boolean sendMessage(Message msg)
        {
            return sendMessageDelayed(msg, 0);
        }
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
        {
            if (delayMillis < 0) {
                delayMillis = 0;
            }
            return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
        }
    
     public boolean sendMessageAtTime(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);
        }
    
    • post Runnable
    public final boolean post(Runnable r)
        {
           return  sendMessageDelayed(getPostMessage(r), 0);
        }
    
     private static Message getPostMessage(Runnable r) {
            Message m = Message.obtain();
            m.callback = r;
            return m;
        }
    
     public final boolean sendMessageDelayed(Message msg, long delayMillis)
        {
            if (delayMillis < 0) {
                delayMillis = 0;
            }
            return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
        }
    
    public boolean sendMessageAtTime(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);
        }
    

    不管是发送消息还是Post Runnable最终都是调用sendMessageAtTime(Message msg, long uptimeMillis)
    然后enqueueMessage(queue, msg, uptimeMillis)入到消息队列中

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    
    

    上面的这个函数函数有很重要的一行msg.target = this, 将当前发送Message的Handler赋值给这个msg的target, 这个target将来在Looper中取得消息后进行分发的Handler对象.

    接下来就是调用MessageQueue的消息入队

    5,MessageQueue的入队操作
     boolean enqueueMessage(Message msg, long when) {
            if (msg.target == null) {
                throw new IllegalArgumentException("Message must have a target.");
            }
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }
    
            synchronized (this) {
                if (mQuitting) {
                    IllegalStateException e = new IllegalStateException(
                            msg.target + " sending message to a Handler on a dead thread");
                    Log.w(TAG, e.getMessage(), e);
                    msg.recycle();
                    return false;
                }
    
                msg.markInUse();
                msg.when = when;
                Message p = mMessages;
                boolean needWake;
                //如果消息队列为空,那么改Message就作为头结点
                if (p == null || when == 0 || when < p.when) {
                    // New head, wake up the event queue if blocked.
                    msg.next = p;
                    mMessages = msg;
                    needWake = mBlocked;
                } else {
                    // Inserted within the middle of the queue.  Usually we don't have to wake
                    // up the event queue unless there is a barrier at the head of the queue
                    // and the message is the earliest asynchronous message in the queue.
                    needWake = mBlocked && p.target == null && msg.isAsynchronous();
                    Message prev;
                  //寻找合适的插入位置,是按照消息的将要被处理的先后顺序来处理的(when)
                    for (;;) {
                        prev = p;
                        p = p.next;
                        if (p == null || when < p.when) {
                            break;
                        }
                        if (needWake && p.isAsynchronous()) {
                            needWake = false;
                        }
                    }
                    msg.next = p; // invariant: p == prev.next
                    prev.next = msg;
                }
    
                // We can assume mPtr != 0 because mQuitting is false.
                if (needWake) {
                    nativeWake(mPtr);
                }
            }
            return true;
        }
    

    MessageQueue插入的Message时候
    1)首先会有各种判断, 消息的target(也就是发送和将来处理消息的Handler)是否为空, Message是否在使用, 消息队列是否退出等前提条件
    2)插入Message到消息队列的合适位置
    如果消息队列为空,那么该Message就作为头结点
    否则就根据消息将要执行的先后顺序(when)来进行比较找到插入的位置

    6,Looper.loop()

    Looper中的loop负责来取出消息队列中的Message,如果消息队列为空,则阻塞,如果调用quit或者quitSafely方法退出消息机制,那么取出的msg为空,将退出. 否则执行消息的派发

    public static void loop() {
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            final MessageQueue queue = me.mQueue;
    
            // Make sure the identity of this thread is that of the local process,
            // and keep track of what that identity token actually is.
            Binder.clearCallingIdentity();
            final long ident = Binder.clearCallingIdentity();
    
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
    
                 ... ... 
                try {
                    msg.target.dispatchMessage(msg);
                } finally {
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
    
                ... ....
                msg.recycleUnchecked();
            }
        }
    

    msg.target.dispatchMessage(msg)中的target就是发送Message到MessageQueue的Handler,所以发送Message到MessageQueue的Handler和Looper从MessageQueue取出Message进行派发处理的也是这个Handler

    7,Handler的dispatchMessage
      public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    这个就是Message最终处理的地方,转了一大圈又回到了原点
    首先分两部分说明他是怎么派发的

    • if (msg.callback != null)
      这个对应的是handler post Runnable对象情况
    private static void handleCallback(Message message) {
            message.callback.run();
     }
    

    这个时候直接执行Runnable对象的run()方法,不会被Handler的handleMessage方法处理

    • msg.callback == null
      这个对应的是handler 发送消息(sendMessage)的情形
      也就是上面的else代码分之
      首先他会判断handler对象中的mCallback是否为空,这个对象类型如下:
     public interface Callback {
            public boolean handleMessage(Message msg);
        }
    这个接口在构造Handler对象的时候使用
     public Handler(Looper looper, Callback callback, boolean async) {
            mLooper = looper;
            mQueue = looper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
       }
    

    如果在创建Handler实例时,传入了Callback接口,如果handleMessage(Message)方法返回true,则截断这个Message向下传递,直接返回.
    如果Callback不为空且返回false或者Callback为空,那么就由我们创建Handler覆写的handleMessage(Message)处理,这个方法是不是很熟悉呢?

    到此,消息机制的创建,以及处理流程完毕,下面用一个图


    ss.png

    四,HandlerThread使用和分析

    HandlerThread提供了一个便于建立子线程消息机制的一种方式.
    使用如下:

     HandlerThread ht = new HandlerThread("sub");
     ht.start();
     Handler handler = new Handler(ht.getLooper());
    

    他很简单的就创建一个子线程,以及这个线程对应的Looper,MessageQueue,然后将一个Handler关联到这个线程和消息队列

    HandleThread代码不多,他的实现精髓就是run()方法和getLooper()方法

    public void run() {
            mTid = Process.myTid();
            Looper.prepare();
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();
            Looper.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;
        }
    
    

    当线程启动,就开始执行run方法 他首先就开始创建一个Looper,然后给变量mLooper赋值,然后notifyAll由于获得Looper被阻塞的线程

    getLooper()方法返回Looper对象,然后关联到Handler对象,建立消息机制.但是由于线程异步,所以可能在获取的时候,Looper对象还没有创建出来,所以有一个wait()操作

    五,Handler总结

    • 每个线程都对应唯一的一个Looper和唯一的一个MessageQueue
    • 每个Looper可以对应多个Handler
    • 每个Handler对应唯一的一个Looper和MessageQueue
    • 那个Handler 发送消息,最终经过hanler->messagequeue->loop->handler回到原点由那个Handler处理
    • 当我们要在子线程中建立消息机制时,推荐使用HandlerThread
    • 当我们在子线程中简历消息机制时,如果不再使用,要调用quit()或者quitSafely()退出

    最后,在举一个🌰来说明这个Handler机制
    假设你所在的公司只有一个领导(Looper), 只有一个OA系统(MessageQueue),多个员工(Handler).
    当你(Handler)有女票千里奔袭机动千里,突然奔袭而来,你(Handler)向OA(MessageQueue)提交请假事由(Message),你的领导(Looper)看到这个不可拒绝的理由(Message),将这个事由派发给你(Handler),然后你(Hanlder)处理---接驾

    六,一些疑问和异常

    1,为什么我们平时使用Handler时候没有写过Looper.prepare()h和Looper.loop()方法呢?

    因为我们平时使用的Handler都是在主线程中创建的, 当应用启动,ActivityThread类中已经初始化了

     public static void main(String[] args) {
            ... ...
            Looper.prepareMainLooper();
    
            ActivityThread thread = new ActivityThread();
            thread.attach(false);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    
         ... ...
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }
    
    2,throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()");

    由于在子线程中创建Handler时候没有初始化对应的Looper(每个Handler要对应一个Looper的)

    3, throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");

    由于在子线程中创建Handler时候,调用Looper.loop()之前一定要调用Looper.prepare()

    相关文章

      网友评论

        本文标题:Android中的Handler机制介绍以及分析

        本文链接:https://www.haomeiwen.com/subject/duziittx.html