zoukankan      html  css  js  c++  java
  • 【转载】每个 Android 开发者必须知道的消息机制问题总结

    Android的消息机制几乎是面试必问的话题,当然也并不是因为面试,而去学习,更重要的是它在Android的开发中是必不可少的,占着举足轻重的地位,所以弄懂它是很有必要的。下面就来说说最基本的东西。

    Looper

    作用:

    • 关联起Thread
    • 循环取出消息

    1、Looper是否可以直接实例化?

    Looper构造方法是私有的,其中做了两件事

    • 创建一个MessageQueue
    • 得到与之对应的Thread
     private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

    2、一个线程能对应多个Lopper?

    不能,一个线程对应一个Looper对象,通过ThreadLocal保证一个线程只有一个Looper与之对应,如果多次调用Looper.prepare();则会抛出运行时异常。

     private static void prepare(boolean quitAllowed) {
       if (sThreadLocal.get() != null) { // 查看是否有looper与当前线程对应
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

    3、Looper是无限循环,会阻塞吗?

    是,当开启一个loop后是一个死循环,从MessageQueue中取出消息,处理消息,但是也有可能退出,在没有消息后退出循环。

      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;
    	// 略
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) { // 当没有消息的时候,退出
                // No message indicates that the message queue is quitting.
                return;
            }
    // 略
            msg.target.dispatchMessage(msg);
       }

    4、可以再次调用Looper.prepareMainLooper吗?

    不可以,Looper.prepareMainLooper最终也是调用prepare(),同2.

    public static void prepareMainLooper() {
        prepare(false); // 创建一个Looper
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been 				prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    5、MainLooper什么时候创建的?

    MainLooper是启动Activity创建ActivityThread(并不是一个Thread)时候创建,所以不能多次创建。

    public static void main(String[] args) {
      // 略
       Process.setArgV0("<pre-initialized>");
      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");
      }
    }

    Handler

    作用:

    • 发送消息到MessageQueue
    • 处理消息

    1、Handler如何与Looper、MessageQueue关联起来?

    我们知道一个Looper对应一个Thread,一个Looper包含一个MessageQueue。当我们创建Handler时就会从当前线程中取出与之对应的Looper,让后在从Looper中取出MessageQueue。

    // 1、自动获取
    public Handler(Callback callback, boolean async) {
     	// 略
        mLooper = Looper.myLooper(); // 取出当前线程中的Looper
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called 						Looper.prepare()");
        }
        mQueue = mLooper.mQueue; // 取出MessageQueue
        mCallback = callback;
        mAsynchronous = async;
    }
    // 2、传递一个Looper进来
    public Handler(Looper looper, Callback callback, boolean async) {
            mLooper = looper;
            mQueue = looper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }

    Message

    单项链表结构。

    作用:

    • 数据的载体

    1、消息如何复用的?

    从全局消息池(链表结构)中

    public static Message obtain() {
       	synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

    2、Message为什么能传递?

    Android中想要传递对象要么实现Serializable要么Parcelable,在这里是实现了Parcelable接口。

    public final class Message implements Parcelable {
      // 略
    }

    3、如何与Handler关联?

    我们知道在消息传机制中Handler充当着“快递员”的角色,那么他又是如何与“货物”--Message发生关系呢?实际上Message有一个成员变量target他的类型正是Handler,

    /*package*/ Runnable callback;
    
    public int arg1; 
    
    public int arg2;
    
    public Object obj;
    
    /*package*/ Handler target; // 关键点

    当我们通过Handler去send一个Message时候最终都会为target赋值为this,即当前的Handler。

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

    另为如果是通过Message.Obtain(),获取的复用Message也会为其赋值。

    多说一句,Handler.obtainMessage()调用的就是Message.Obtain()。

    public final Message obtainMessage(){
        return Message.obtain(this);
    }

    总结:

    通过一系列的包涵关系,最终Looper、Handler、Message、MessageQueue即发生关联,从而形成一个闭合,开启消息循环。

    困惑

  • 相关阅读:
    笔记44 Hibernate快速入门(一)
    tomcat 启用https协议
    笔记43 Spring Security简介
    笔记43 Spring Web Flow——订购披萨应用详解
    笔记42 Spring Web Flow——Demo(2)
    笔记41 Spring Web Flow——Demo
    Perfect Squares
    Factorial Trailing Zeroes
    Excel Sheet Column Title
    Excel Sheet Column Number
  • 原文地址:https://www.cnblogs.com/wust221/p/5823987.html
Copyright © 2011-2022 走看看