你的位置:首页 > 操作系统

[操作系统]android 进程/线程管理(四)续


继续分析handler 和looper

先看看handler的

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

所以消息的处理分层三种,就是

1.传入一个runnable让handler处理。

2.传入要处理的hanglemessage

3.或者子类复写handlermessage。

其实本质是一样的,就是把怎么处理的这个方法,在dispatchMessage的时候分发。

如果我们有特殊的需求,完全可以重写dispatchMessage,分发给我们需要的方法。

 

  public static Message obtain() {    synchronized (sPoolSync) {      if (sPool != null) {        Message m = sPool;        sPool = m.next;        m.next = null;        sPoolSize--;        return m;      }    }    return new Message();  }

obtainMessage()方法提供了一个消息池,以防止消息过多产生的内存问题。这个池是static的,也就是所有app共享的。 
每次获取消息,poolsize就会减一。然后在looper.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;    // 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;      }      // This must be in a local variable, in case a UI event sets the logger      Printer logging = me.mLogging;      if (logging != null) {        logging.println(">>>>> Dispatching to " + msg.target + " " +            msg.callback + ": " + msg.what);      }      msg.target.dispatchMessage(msg);      if (logging != null) {        logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);      }      // Make sure that during the course of dispatching the      // identity of the thread wasn't corrupted.      final long newIdent = Binder.clearCallingIdentity();      if (ident != newIdent) {        Log.wtf(TAG, "Thread identity changed from 0x"            + Long.toHexString(ident) + " to 0x"            + Long.toHexString(newIdent) + " while dispatching to "            + msg.target.getClass().getName() + " "            + msg.callback + " what=" + msg.what);      }      msg.recycle();    }  }

loop
  public void recycle() {    clearForRecycle();    synchronized (sPoolSync) {      if (sPoolSize < MAX_POOL_SIZE) {        next = sPool;        sPool = this;        sPoolSize++;      }    }  }

释放这条已经使用过的消息。

线程池的概念也是如此。

 

下面我们看看looper:

Looper就是thread里面跑起消息机制的东西,顾名思义,“循环”。

如我写的demo,没有looper这个东东,也是可以实现消息循环的,那android为什么还要搞这么个类出来。

我想是基于如下的原因:

1.我在工作线程中,怎么发消息到主线程。

handler传入getMainLooper(),然后就可以发消息到主线程,进行UI更新等操作。

handler里面的looper绑定了queue。所以hander会给main messagequeue发送消息。

2.代码的提炼,既然循环的过程都是相同的,完全可以把这个过程提炼出来。

@Override  public void run() {    TraceLog.i("MyLoopThread looper prepare");    Looper.prepare();    myLooper = Looper.myLooper();    mHandler = new MyHandler(myLooper);    Looper.loop();  }

只要如此简单的几句code,thread里面就已经搭建好了消息系统,实在是太神奇了!

再来看看looper.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;    // 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;      }      // This must be in a local variable, in case a UI event sets the logger      Printer logging = me.mLogging;      if (logging != null) {        logging.println(">>>>> Dispatching to " + msg.target + " " +            msg.callback + ": " + msg.what);      }      msg.target.dispatchMessage(msg);      if (logging != null) {        logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);      }      // Make sure that during the course of dispatching the      // identity of the thread wasn't corrupted.      final long newIdent = Binder.clearCallingIdentity();      if (ident != newIdent) {        Log.wtf(TAG, "Thread identity changed from 0x"            + Long.toHexString(ident) + " to 0x"            + Long.toHexString(newIdent) + " while dispatching to "            + msg.target.getClass().getName() + " "            + msg.callback + " what=" + msg.what);      }      msg.recycle();    }  }

loop

这里有几个关键点:

 Message msg = queue.next(); // might block

首先,这句之前有过分析,就是当消息队列没有消息的时候,会block住,直到有消息传过来。

 msg.target.dispatchMessage(msg);

每条消息只有一个处理位置,就是发送他的handler

 msg.recycle();

消息结束后释放,这样整个消息池就可以循环使用了。

 

可以说android的消息机制是参考的许多成熟的消息机制的基础上,创建而成的,有位难得的是,

他不仅仅是操作系统的使用,更是给我们android 应用开发者使用的一套工具。

学习android源码,对我们自己搭建消息机制有很大的借鉴作用。

 

参考:

1.《深入理解android内核设计思想》林学森

2.《Android内核剖析》

 

相关文章:

android 进程/线程管理(一)----消息机制的框架

android 进程/线程管理(二)----关于线程的迷思

android 进程/线程管理(三)----Thread,Looper / HandlerThread / IntentService