上一篇文章,我们讲到在调用Handler的sendMessage方法时,最终我们会进入到一个叫 sendMessageAtTime的方法,如下:

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

在这里,我们看到了MessageQueue和enqueueMessage等变量跟方法,我们可以想到,在Handler的实现的机制中,一定存在着一个消息队列,而它存放了我们创建的众多消息(Message)对象。

从这里,我们就会开始去探寻隐藏在 Handler对象后面的那一些我们想知道的实现机制了。

首先,我们还是从 Handler的创建开始说起,在上一篇文章,我们是通过 new Handler的方法来创建的,代码如下:

    private Handler mHandler = new Handler() {        public void handleMessage(Message msg) {            switch (msg.what) {            case MSG_ID_1:                Log.v("Test", "Toast called from Handler.sendMessage()");                break;            case MSG_ID_2:                String str = (String) msg.obj;                Log.v("Test", str);                break;            }                    }    };

显然,我们要去看一下Handler的构造函数,如下:

    public Handler() {        this(null, false);    }    public Handler(Callback callback) {        this(callback, false);    }    public Handler(Looper looper) {        this(looper, null, false);    }        public Handler(Looper looper, Callback callback) {        this(looper, callback, false);    }       public Handler(boolean async) {        this(null, async);    }    public Handler(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 that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;        mAsynchronous = async;    }        public Handler(Looper looper, Callback callback, boolean async) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = callback;        mAsynchronous = async;    }

我们可以看到,真正实现的构造函数,其实只有下面两个,如下:

    public Handler(Callback callback, boolean async) {        ....    }        public Handler(Looper looper, Callback callback, boolean async) {        ...    }

这两个的差别就在于是否有参数Looper,而Looper是一个线程相关的对象。

何谓线程相关的变量?就是线程间不能共享的对象,只在本线程内有作用的对象。

那么Looper对象的作用是什么?

从我个人的理解,Looper类就是对MessageQueue的封装,它主要做的是两件事:

1)构造Looper对象,初始化MessageQueue,我们可以从其构造函数看到:

    private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mThread = Thread.currentThread();    }


显然,MessageQueue正是在创建Looper的时候初始化的。

我们还注意到,这个构造函数是private的,而它则是被Looper.prepare方法调用的,如下:

    public static void prepare() {        prepare(true);    }    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));    }

可以看到,Loop对象被创建之后,会被放到ThreadLocal变量中,而ThreadLocal正是线程局部变量,这说明了关于Looper的一个特性:

每一个线程中都只能有一个Looper对象。

2)调用loop()方法,循环处理消息,具体代码如下:

    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);           ....            msg.recycle();        }    }

从上面的代码中,我们可以看到,在一个无限循环中,会从MessageQueue中获得消息,然后通过msg.target.dispatchMessage(msg)方法调用,处理消息,最后将消息进行回收。

在这里,我们先不关心dispatchMessage方法,我们先跑一下题,看一下recycle方法里面做了什么事吧,如下:

    private static Message sPool;    private static int sPoolSize = 0;    private static final int MAX_POOL_SIZE = 50;    /**     * Return a new Message instance from the global pool. Allows us to     * avoid allocating new objects in many cases.     */    public static Message obtain() {        synchronized (sPoolSync) {            if (sPool != null) {                Message m = sPool;                sPool = m.next;                m.next = null;                sPoolSize--;                return m;            }        }        return new Message();    }        public void recycle() {        clearForRecycle();        synchronized (sPoolSync) {            if (sPoolSize < MAX_POOL_SIZE) {                next = sPool;                sPool = this;                sPoolSize++;            }        }    }

从上面的代码中,我们可以看到,Message对象本身有一个next的字段指向另外一个Message,也就是说,可以通过链表的方式将众多的Message给串起来,变成一个链表的消息池sPool。

而在这里,当调用recycle方法,就会将当前Message对象,先clearForRecycle之后,再添加到 sPool的头部中,而当我们通过Message的obtain方法的时候,我们其实也是从sPool中拿 出一个空的Message对象。

相信看到这里,大家就了解了上一篇文章中我说,为什么建议大家使用Message.obtain方法去获取消息对象了吧。

接下来,我们再回到正题上。

从上面关于Handler的创建和关于Looper的描述中,我们可以得出这样一个结论:

在每一个线程中,如果我们要创建Handler,那么此线程中就必须有一个Looper对象,而这个Looper对象中又封装了一个MessageQueue对象来对Message进行管理。

所以,如果我们要在一个新线程中使用handler的话,我们就必须通过调用Loop.prepare()方法,为此线程创建一个Looper对象,官方给出的代码如下:

  class LooperThread extends Thread {      public Handler mHandler;        public void run() {          Looper.prepare();            mHandler = new Handler() {              public void handleMessage(Message msg) {                  // process incoming messages here              }          };            Looper.loop();      }  }

当然,只有理论当然是不行的,我们还是得通过一个例子来看一下具体的效果,如下:

public class MainActivity extends ActionBarActivity {    private static final int MSG_ID_1 = 1;    private static final int MSG_ID_2 = 2;    class LooperThread extends Thread {        public Handler mHandler;        public void run() {            Looper.prepare();                mHandler = new Handler() {                                public void handleMessage(Message msg) {                    Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId());                    switch (msg.what) {                    case MSG_ID_1:                        Log.v("Test", "Toast called from Handler.sendMessage()");                        break;                    case MSG_ID_2:                        String str = (String) msg.obj;                        Log.v("Test", str);                        break;                    }                }            };            Looper.loop();        }    }        protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId());                LooperThread looperThread = new LooperThread();        looperThread.start();                while(looperThread.mHandler == null){                                }                Message message = Message.obtain();        message.what = MSG_ID_1;        looperThread.mHandler.sendMessage(message);        Message msg2 = Message.obtain();        msg2.obj = "I'm String from Message 2";        msg2.what = MSG_ID_2;        looperThread.mHandler.sendMessage(msg2);    }}

对应的结果如下:

10-27 16:48:44.519: V/Test(20837): Id of MainThread : 110-27 16:48:44.529: V/Test(20837): Id of LooperThread : 6842110-27 16:48:44.529: V/Test(20837): Toast called from Handler.sendMessage()10-27 16:48:44.529: V/Test(20837): Id of LooperThread : 6842110-27 16:48:44.529: V/Test(20837): I'm String from Message 2

那其实在这里有一个问题,为什么我们平常可以直接去创建Handler对象,而不需要去调用UI线程的Looper.prepare和loop等方法呢?

当然,这肯定也是需要的,只是这一步是由Android系统帮我们做了,所以默认的主线程就不再需要去做这些初始化。

好了,这一篇文章,我们就了解了关于线程,Looper,Handler, MessageQueue 和 Message 等之间的一些关联,而主要是对于Looper对象的认识。

结束。

更多相关文章

  1. Android(安卓)完全退出应用程序back和home键
  2. Android(安卓)Studio中如何解决重复依赖导致的app:transformClas
  3. Android常见的几种RuntimeException
  4. 手机锁屏后再解锁保存activity状态
  5. 使用ImageSpan图标不截断的方法
  6. Android在线程中创建一个POST请求
  7. Handler消息传递机制(子线程中传递new Handler和主线程中new Hand
  8. Android(安卓)进阶——Framework 核心四大组件之跨进程共享组件C
  9. Gradle Error: Connection timed out 无法获取远程依赖解决方法(2

随机推荐

  1. Java反射
  2. Android实现局域网组播
  3. Common Intents
  4. 接口 登录、注册、信息
  5. android自定义一圆角ImageView
  6. 调用摄像头拍照并显示
  7. android 读中文文本文件
  8. Android抽屉(SlidingDrawer)的实现
  9. Android中的数据存储方式
  10. Android中获取全局Context