星空网 > 软件开发 > 操作系统

Handler、Looper、MessageQueue、Thread源码分析

  关于这几个之间的关系以及源码分析的文章应该挺多的了,不过既然学习了,还是觉得整理下,印象更深刻点,嗯,如果有错误的地方欢迎反馈。

  转载请注明出处:http://www.cnblogs.com/John-Chen/p/4396268.html

 

对应关系:

 Handler、Looper、MessageQueue、Thread源码分析images/loading.gif' data-original="file:///var/folders/7f/h1ysmtyj7csd81gcg2d5dkmr0000gn/T/cn.wiz.wiznoteformac/WizNote/31c905b3-2d99-457a-b64c-6a1e50b43429/index_files/7e9ea72e-86e5-4ff1-8a22-3ab21e2a3993.png" border="0" />Handler、Looper、MessageQueue、Thread源码分析 Handler、Looper、MessageQueue、Thread源码分析

 

1、Handler

    不带Looper的构造器

   /**   * Use the {@link Looper} for the current thread with the specified callback interface   * and set whether the handler should be asynchronous.   *   * Handlers are synchronous by default unless this constructor is used to make   * one that is strictly asynchronous.   *   * Asynchronous messages represent interrupts or events that do not require global ordering   * with represent to synchronous messages. Asynchronous messages are not subject to   * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.   *   * @param callback The callback interface in which to handle messages, or null.   * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for   * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.   */  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(); //myLooper() return sThreadLocal.get(), mLooper每个线程独有,腾讯有次面试问到了    if (mLooper == null) {      //Handler创建时必须有Looper对象      throw new RuntimeException(        "Can't create handler inside thread that has not called Looper.prepare()");    }    mQueue = mLooper.mQueue;    mCallback = callback;    mAsynchronous = async;  }

 

 

“In Android, Handler classes should be static or leaks might occur.”:

public class MainActivity extends ActionBarActivity {  //warn:In Android, Handler classes should be static or leaks might occur.  private final Handler handler = new Handler(){    @Override    public void handleMessage(Message msg) {      super.handleMessage(msg);    }  };}

原因:

no-static的内部类handler会隐式的持有当前类MainActivity的一个引用,Handler 的 post/sendMessage 系列方法最后都是通过转调 MessageQueue 的 enqueueMessage 来实现的,每个Message都持有一个Handler的引用(Message.target),所以最终会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被引用而无法被回收。

解决办法:

1、在关闭Activity的时候停掉与Handler有关的后台线程;

2、如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了;

3、将Handler声明为静态类:

static class MyHandler extends Handler {    WeakReference<Activity> mActivityReference;    MyHandler(Activity activity) {      mActivityReference= new WeakReference<Activity>(activity);    }    @Override    public void handleMessage(Message msg) {      final Activity activity = mActivityReference.get();      if (activity != null) {        //......      }    }  };

  


2、Looper

一个典型的Loop Thread实现:

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

 

 

变量:

//sThreadLocal变量保证looper对象每个线程独享,prepare()中set值// sThreadLocal.get() will return null unless you've called prepare().static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//通过Loop.class管理private static Looper sMainLooper; // guarded by Looper.class//对应1个消息队列final MessageQueue mQueue;//对应1个线程final Thread mThread;

 

 

Looper构造器:

   //Main thread not allowed to quit  private Looper(boolean quitAllowed) {    //创建一个消息队列    mQueue = new MessageQueue(quitAllowed);    mThread = Thread.currentThread();  }

 

 

 

Looper方法:

/** Initialize the current thread as a looper.   * This gives you a chance to create handlers that then reference   * this looper, before actually starting the loop. Be sure to call   * {@link #loop()} after calling this method, and end it by calling   * {@link #quit()}.   */  public static void prepare(){    prepare(true);  }   private static void prepare(boolean quitAllowed){    if (sThreadLocal.get() != null) {      //每个线程只能有1个Looper对象      throw new RuntimeException("Only one Looper may be created per thread");    }    //线程内创建一个Looper对象    sThreadLocal.set(new Looper(quitAllowed));  }   /**   * Run the message queue in this thread. Be sure to call   * {@link #quit()} to end the loop.   */  public static void loop() {    final Looper me = myLooper();    if (me == null) {      //必须先调用Looper.prepare()      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.        //没有消息表示消息队列已终止,即已调用mQueue.quit(true),消息循环终止        return;      }      ......      msg.target.dispatchMessage(msg); //通过handler分发消息      ......       msg.recycleUnchecked(); //Recycles a Message that may be in-use    }  }

 

 

MainLooper

  /**   * Initialize the current thread as a looper, marking it as an   * application's main looper. The main looper for your application   * is created by the Android environment, so you should never need   * to call this function yourself. See also: {@link #prepare()}   */  public static void prepareMainLooper() {    prepare(false);    synchronized (Looper.class) {      if (sMainLooper != null) {        throw new IllegalStateException("The main Looper has already been prepared.");      }      sMainLooper = myLooper();    }  }   /** 
    Returns the application's main looper, which lives in the main thread of the application. */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } }

 

 

ActivityThread.main:

public static void main(String[] args) {    SamplingProfilerIntegration.start();    // CloseGuard defaults to true and can be quite spammy. We    // disable it here, but selectively enable it later (via    // StrictMode) on debug builds, but using DropBox, not logs.    CloseGuard.setEnabled(false);    Environment.initForCurrentUser();    // Set the reporter for event logging in libcore    EventLogger.setReporter(new EventLoggingReporter());    Security.addProvider(new AndroidKeyStoreProvider());    // Make sure TrustedCertificateStore looks in the right place for CA certificates    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());    TrustedCertificateStore.setDefaultUserDirectory(configDir);    Process.setArgV0("<pre-initialized>");    //主线程中,系统已经帮我们自动调用了Looper.prepare()方法,所以在主线程中可以直接创建Handler对象    Looper.prepareMainLooper();    ActivityThread thread = new ActivityThread();    thread.attach(false);    if (sMainThreadHandler == null) {      sMainThreadHandler = thread.getHandler();    }    AsyncTask.init();    if (false) {      Looper.myLooper().setMessageLogging(new          LogPrinter(Log.DEBUG, "ActivityThread"));    }
Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }

 

 

3、消息队列MessageQueue

底层实现:

android/frameworks/base/core/jni/android_os_MessageQueue.h

android/frameworks/base/core/jni/android_os_MessageQueue.cpp

epoll模型找到几篇不错的文章:

http://blog.chinaunix.net/uid-7944836-id-2938541.html

http://blog.csdn.net/ashqal/article/details/31772697

http://book.2cto.com/201208/1946.html

 

 

Message是链表结构:

public final class Message implements Parcelable {  public int what;  public int arg1;   public int arg2;  public Object obj;  public Messenger replyTo;  public int sendingUid = -1;  /*package*/ static final int FLAG_IN_USE = 1 << 0;  /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;  /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;  /*package*/ int flags;  /*package*/ long when;  /*package*/ Bundle data;  /*package*/ Handler target;  /*package*/ Runnable callback;  /*package*/ Message next;  ......}

 

 

MessageQueue变量:

// True if the message queue can be quit. //与 Looper.prepare(boolean quitAllowed) 中参数含义一致,是否允许中止,主线程的消息队列是不允许中止的private final boolean mQuitAllowed;//MessageQueue 是通过调用 C++ native MessageQueue 实现的,mPtr是指向native MessageQueue的指针private long mPtr; // used by native code//消息链表Message mMessages;//表示当前队列是否处于正在退出状态private boolean mQuitting;// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.//表示next()调用是否被block在timeout不为0的pollOnce上private boolean mBlocked;

  

 

MessageQueue构造函数:

MessageQueue(boolean quitAllowed) {    mQuitAllowed = quitAllowed;    mPtr = nativeInit();}

 

 

 

native函数:

//创建 NativeMessageQueue 对象,并将这个对象的指针复制给 Android MessageQueue 的 mPtrprivate native static long nativeInit();//通过等待被激活,然后从消息队列中获取消息private native static void nativePollOnce(long ptr, int timeoutMillis);//激活处于等待状态的消息队列,通知它有消息到达了private native static void nativeWake(long ptr);//消息队列是否是空置状态private native static boolean nativeIsIdling(long ptr);//销毁消息队列private native static void nativeDestroy(long ptr);

 

 

//添加消息

boolean enqueueMessage(Message msg, long when) {    //检测消息的合法性,必须有Handler对象以及未处理    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("MessageQueue", e.getMessage(), e);        msg.recycle();        return false;      }       msg.markInUse();      msg.when = when;      Message p = mMessages;      boolean needWake;      //按照时间从小到大,when == 0插入到头部      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.        //当前消息队列已经处于 Blocked 状态,且队首是一个消息屏障(和内存屏障的理念一样,        //这里是通过 p.target == null 来判断队首是否是消息屏障),并且要插入的消息是所有异步消息中最早要处理的        //才会 needwake 激活消息队列去获取下一个消息        needWake = mBlocked && p.target == null && msg.isAsynchronous();        Message prev;        //根据时间插入到链表的合适位置        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;  }

 

 


Handler 的 post/sendMessage 系列方法最后都是通过转调 MessageQueue 的 enqueueMessage 来实现的:

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);  } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {    msg.target = this;    if (mAsynchronous) {      msg.setAsynchronous(true);    }    return queue.enqueueMessage(msg, uptimeMillis);  }

Handler 中与Message 相关的静态方法也都是通过 MessageQueue 的对应的静态方法实现的,比如 removeMessages, hasMessages, hasCallbacks 等等。

 

 

//取消息

Message next() {    // Return here if the message loop has already quit and been disposed.    // This can happen if the application tries to restart a looper after quit    // which is not supported.    final long ptr = mPtr;    if (ptr == 0) {      //已经dispose()      return null;    }    int pendingIdleHandlerCount = -1; // -1 only during first iteration    int nextPollTimeoutMillis = 0;
for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); }
nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { // Stalled by a barrier. Find the next asynchronous message in the queue. do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // Next message is not ready. Set a timeout to wake up when it is ready. nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // Got a message. mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); return msg; } } else { // No more messages. nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // If first time idle, then get the number of idlers to run. // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // Run the idle handlers. // We only ever reach this code block during the first iteration. for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf("MessageQueue", "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; } }

 



 

void quit(boolean safe) {    if (!mQuitAllowed) {      throw new IllegalStateException("Main thread not allowed to quit.");    }    synchronized (this) {      if (mQuitting) {        return;      }      mQuitting = true;      if (safe) {        removeAllFutureMessagesLocked();      } else {        removeAllMessagesLocked();      }      // We can assume mPtr != 0 because mQuitting was previously false.      nativeWake(mPtr);    }  }

 

 

 


IdleHandler:

IdleHandler接口表示当MessageQueue发现当前没有更多消息可以处理的时候则顺便干点别的事情的callback函数(即如果发现idle了,

那就找点别的事干)。

callback函数有个boolean的返回值,表示是否keep。如果返回false,则它会在调用完毕之后从mIdleHandlers

中移除。

ActivityThread.java里的一个内部类,代码如下:

final class GcIdler implements MessageQueue.IdleHandler {    @Override    public final boolean queueIdle() {      doGcIfNeeded();      return false;    }  }

 

这是一个gc相关的IdleHandler,即如果没有更多的消息可以处理就会抽空doGcIfNeeded(),最后返回false表示不保留在mIdleHandlers

中,即用一次就扔了,只执行一遍。



 

参考文章:

http://www.cnblogs.com/kesalin/p/android_messagequeue.html

http://www.cnblogs.com/xiaoweiz/p/3674836.html

 




原标题:Handler、Looper、MessageQueue、Thread源码分析

关键词:

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流