频道栏目
首页 > 资讯 > Android > 正文

Android源码-Handler分析

18-06-20        来源:[db:作者]  
收藏   我要投稿

Handler简介

Handler是Android消息机制的上层接口,多数开发者会使用Handler去更新UI或做延时处理。如下代码所示:

new Thread(new Runnable() {
 @Override
 public void run() {
  // do something
  handler.sendMessage(message)
 }
}).start();
new Handler().postDelayed(new Runnable() {
  @Override
  public void run() {
//do something
  }
 }, 2000);

Handler分析

Handler类位于android.os包下,继承Object类

其中可见的构造方法有三个

/**
 * Constructor associates this handler with the {@link Looper} for the
 * current thread and takes a callback interface in which you can handle
 * messages.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 *
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Callback callback) {
 this(callback, false);
}

/**
 * Use the provided {@link Looper} instead of the default one.
 *
 * @param looper The looper, must not be null.
 */
public Handler(Looper looper) {
 this(looper, null, false);
}

/**
 * Use the provided {@link Looper} instead of the default one and take a callback
 * interface in which to handle messages.
 *
 * @param looper The looper, must not be null.
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Looper looper, Callback callback) {
 this(looper, callback, false);
}

其中Callback是Handler内部定义的接口,只有一个回调方法handleMessage

/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
  public interface Callback {
public boolean handleMessage(Message msg);
  }

这里先来分析无参构造方法

public Handler() {
 this(null, false);
}

在无参构造方法中调用了重载方法,如下,省略部分代码:

/**
  * 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 respect 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.
  *
  * @hide
  */
 public Handler(Callback callback, boolean async) {
  ....//省略
  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;
 }

这里需要注意下@hide修饰为隐藏方法,不能直接调用,可以通过反射调用。

这里需要一个Looper对象,如果mLooper属性为空,会抛出异常。如果在主线程(UI线程)中创建Handler对象,默认在主线程中已经调用了Looper.prepareMainLooper()方法,详细代码在ActivityThread类中main方法中。Looper.myLooper()方法会获取当前线程的Looper对象,当当前线程中没有Looper对象时,创建Handler会抛出异常,这就是常见于在子线程中创建Handler之前没有调用Looper.prepare()方法出现的崩溃,有问题代码如下:

new Thread(new Runnable() {
 @Override
 public void run() {
  Handler mHandler = new Handler();
 }
}).start();

正确在子线程中创建Handler如下:

new Thread(new Runnable() {
@Override
public void run() {
 Looper.prepare();
 Handler mHandler = new Handler();
 Looper.loop();
}
  }).start();

这里需要注意的是在创建完Handler后,这里又调用了Looper.loop()方法,这个方法是为了在这个线程中运行消息队列。

Looper分析

我们可以查看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));
 }

当我们调用Looper.prepare方法时,调用重载方法,为当前线程关联一个新的Looper对象,这里使用的是ThreadLocal,有兴趣的可以查看下源码。我们接着看Looper.loop方法:

/**
  * 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) {
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
final Printer logging = me.mLogging;
if (logging != null) {
 logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}

final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
 Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
 msg.target.dispatchMessage(msg);
 end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
 if (traceTag != 0) {
  Trace.traceEnd(traceTag);
 }
}
if (slowDispatchThresholdMs > 0) {
 final long time = end - start;
 if (time > slowDispatchThresholdMs) {
  Slog.w(TAG, "Dispatch took " + time + "ms on "
 + Thread.currentThread().getName() + ", h=" +
 msg.target + " cb=" + msg.callback + " msg=" + msg.what);
 }
}

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

这里主要逻辑是获取当前Looper对象的MessageQueue队列,for死循环不断的从队列中取出消息,调用msg.target.dispatchMessage(msg);这个的target就是Handler对象,这个target是在Handler中sendMessage系列方法中设置引用的,代码如下:

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

msg.target = this,到这里对Handler的调用关系就分析完毕了。

相关TAG标签
上一篇:win10系统下安装ubuntu双系统的方法
下一篇:NHibernate和MySQL的交互实践
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站