美文网首页Android异步处理
Android异步处理机制:Handler,Looper,Mes

Android异步处理机制:Handler,Looper,Mes

作者: 狮_子歌歌 | 来源:发表于2016-07-19 21:25 被阅读53次

    Android异步处理机制:Handler,Looper,MessageQueue

    异步处理消息概念:

    异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。

    Handler,Looper,MessageQueue三者的关系

    每一个线程都拥有一个Looper对象,每一个Looper对象都持有一个MessageQueue(先进先出)。一个Looper可以和多个线程的Handler绑定起来。总结:Looper的创建会持有一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中获取消息,而消息的发送者可以是一个或者多个Handle。


    解析

    Looper

    Looper的构造方法

    private Looper(boolean quitAllowed) {
            //创建了一个消息队列  
            mQueue = new MessageQueue(quitAllowed);  
            mRun = true;  
            mThread = Thread.currentThread();  
    }  
    

    Looper.prepare()

    public static final void prepare() {
            //sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量  
            if (sThreadLocal.get() != null) {  
                throw new RuntimeException("Only one Looper may be created per thread");  
            }  
            sThreadLocal.set(new Looper(true));  
    }  
    

    说明一个looper对象与对应线程绑定,且该线程有且仅有一个looper对象。如果第二次调用looper.prepare()方法会抛出异常。

    Looper.loop()

    public static void loop() {  
            final Looper me = myLooper();
            //如果me为null说明在调用loop()方法之前没有为当前线程创建Looper对象,抛出异常。  
            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();  
            //进入无限循环,不断的从messageQueue中获取消息
            for (;;) {
                //从队列获取消息  
                Message msg = queue.next(); // might block 
                //如果消息是空,则队列中没有消息,return结束loop()方法,线程阻塞等待 
                if (msg == null) {  
                    // No message indicates that the message queue is quitting.  
                    return;  
                }  
      
                ...  
                //使用调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理。msg中的target就是handle。
      
                msg.target.dispatchMessage(msg);  
      
                ...  
                //释放消息占据的资源
      
                msg.recycle();  
            }  
    } 
    /**
    *获取线程ThreadLocal属性存储的looper对象
    **/ 
    public static Looper myLooper() {
            return sThreadLocal.get();
    }
    

    综上所述,looper的作用就是与当前线程绑定,并且该线程只有一个looper。同时,looper持有一个MessageQueue,有且仅有一个。loop()方法无限循环的从MessageQueue中读取消息,并将message交给message的target的dispatchMessage(msg)处理。

    Handler

    Handler的构造方法

    在使用Handler之前,我们必须对其实例化。

    Handler必须和线程绑定在一起,在初始化Handler的时候一般通过指定Looper对象来绑定looper所在的线程,即给Handler指定Looper对象等于绑定到了Looper对象所在的线程中。Handler的消息处理回调会在该线程中执行。

    public Handler() {  
            this(null, false);  
    }  
    public Handler(Callback callback, boolean async) {  
            ... 
            //首先获取当前线程保存的looper对象,
            mLooper = Looper.myLooper();  
            if (mLooper == null) {  
                throw new RuntimeException(  
                    "Can't create handler inside thread that has not called Looper.prepare()");  
            }  
            //然后与该looper持有的MessageQueue绑定。
            mQueue = mLooper.mQueue;  
            mCallback = callback;  
            mAsynchronous = async;  
        }
    

    如果没有指定looper,那么handler会与当前创建handler的线程绑定,其消息回调处理也在该线程中执行。
    可以通过Looper.myLoop()得到当前线程的looper对象或者调用Looper.getMainLooper()获得主线程的looper对象。

    Handler向MessageQueue发送消息

    handler send

    最常用的sendMessage()方法

    public final boolean sendMessage(Message msg) {  
         return sendMessageDelayed(msg, 0);  
    }  
    
    
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {  
         Message msg = Message.obtain();  
         msg.what = what;  
         return sendMessageDelayed(msg, delayMillis);  
    } 
     
     
    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);  
    }  
    

    最后调用了sendMessageAtTime,在此方法内部直接获取MessageQueue然后调用了enqueueMessage方法

    
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            //将handler实例赋值给msg的target属性。  
           msg.target = this;  
           if (mAsynchronous) {  
               msg.setAsynchronous(true);  
           }  
           //调用消息队列的enqueueMessage()方法,
           //就是将handler发送的消息保存到消息队列中去
           return queue.enqueueMessage(msg, uptimeMillis);  
    } 
    
    

    Looper的loop()方法会取出每个msg然后执行msg.target.dispatchMessage(msg)去处理消息,其实就是派发给相应的Handler。

    Handler工作流程:在线程中通过Looper.prepare()方法为当前线程创建Looper对象,并调用Looper.loop()方法无限循环地从messageQueue中获取handler发送过来的消息,并回调handler。dispatchMessage()方法

    public void dispatchMessage(Message msg) {  
        if (msg.callback != null) {  
            handleCallback(msg);  
        } else {  
            if (mCallback != null) {  
                if (mCallback.handleMessage(msg)) {  
                    return;  
                }  
            }
            //调用handler的sendMessage()方法,在源码中是一个空方法体。
            //也就是我们在实例化Handler对象时,需要去覆写它,实现自己的处理逻辑。  
            handleMessage(msg);  
        }  
    } 
    

    注:在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢?这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。

    Handler post
    mHandler.post(new Runnable()  
            {  
                @Override  
                public void run()  
                {  
                    Log.e("TAG", Thread.currentThread().getName());  
                    mTxt.setText("yoxi");  
                }  
            });
    

    Handler.post()方法中Runnable并没有创建线程。在这个run()方法中可以更新UI。其实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;  
    }  
    

    由此可见,源码中只是将Runnable对象作为message的callback属性。

    注:产生一个Message对象,可以new ,也可以使用Message.obtain()方法;两者都可以,但是更建议使用obtain方法,因为Message内部维护了一个Message池用于Message的复用,避免使用new 重新分配内存。

    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);  
    }  
    

    最终和handler.sendMessage一样,调用了sendMessageAtTime,然后调用了enqueueMessage方法,给msg.target赋值为handler,最终加入MessagQueue.
    由于在getPostMessage()方法中我们给message的callback属性赋值(Runnable),所以这里需要进行判断到底回调handler还是runnable。

    public void dispatchMessage(Message msg) { 
         //判断message对象的callback属性是否存在,若存在执行handlerCallback()方法。
         //即调用runnable 
        if (msg.callback != null) {  
            handleCallback(msg);  
        } else {  
            if (mCallback != null) {  
                if (mCallback.handleMessage(msg)) {  
                    return;  
                }  
            }  
            handleMessage(msg);  
        }  
    } 
    

    MessageQueue

    消息队列,用于存放handler发送过来的message
    MessageQueue.enqueueMessage()方法将handler发送的消息插入队列中。MessageQueue.next()将消息按照先进先出的顺序取出。

    总结

    为了实现Android的UI线程安全,UI的相关操作只能在主线程(UI线程)中操作。但在开发中,需要开启多线程处理耗时操作,又要修改UI,所以就有了Handler传递机制。

    [主线程(UI线程)定义:当程序第一次启动时,Android会同时启动一条主线程(Main Thread)
    作用:主线程主要负责处理与UI相关的事件,所以主线程又叫UI线程)]

    使用runOnUIThread()方法更新UI

    public final void runOnUiThread(Runnable action) {  
            if (Thread.currentThread() != mUiThread) {  
                mHandler.post(action);  
            } else {  
                action.run();  
            }  
        } 
    

    从源码来看,首先判断当前线程是否是UI线程,如果不是,通过主线程的Handler来发送Runnable对象,实现当前线程与UI线程之间的信息传递;若当前线程是UI线程,则直接调用执行Runnable的run()方法。

    参考文献

    鸿洋大神文章

    相关文章

      网友评论

        本文标题:Android异步处理机制:Handler,Looper,Mes

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