android高级---->Handler的原理

时间:2020-12-09 22:17:26

  andriod提供了Handler来满足线程间的通信,上次在更新UI的时候也提到过Handler的使用,关于Handler的基本使用,参见博客(android基础---->子线程更新UI).今天我们深入Handler的源码,了解一个Handler的内部执行原理。

目录导航

  1. Handler简单说明
  2. ActivityThread的说明
  3. Handler的预备分析
  4. Handler的原理分析
  5. 友情链接

Handler简单说明

一、 在Handler的原理说明之前,我们列出相关的重要的类:

  • Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
  • Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
  • MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
  • Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
  • Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

二、 Handler主要有两种用途:

  • 合理调度安排消息和runnable对象,使它们在将来的某个点被执行。
  • 将一个动作入队安排在非当前线程执行。

三、 Handler创建消息

  每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。

四、 Handler发送消息

android高级---->Handler的原理

  UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。

五、 Handler处理消息

  UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。注意handler是主线程中的类。

android高级---->Handler的原理

ActivityThread的说明

一、 Android的一个apk在打开时,使用到的第一个类就是这个类。

这里我们不深入Android应用程序的启动原理了,ActivityThread是一个final类,不是一个线程类:

public final class ActivityThread 

二、 ActivityThread在创建的时候同时也启动了一个线程,这个线程就是一个异步线程。

他创建出了MessageQueue,并同时进行消息的轮 询,因此当这个应用程序在运行时,这个线程是一直都在的。这个线程就是应用程序的主线程,UI的处理等都是在这个线程处理的。在AcitivityThread这个类的是有一个main方法的。我们知道java应用程序的入口就是main方法。这就是程序的入口。我们来看ActivityThread的源代码:

public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
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()); AndroidKeyStoreProvider.install(); // 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.prepareMainLooper(); ActivityThread thread = new ActivityThread();
thread.attach(false); if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
} if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
} // End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited");
}

  这里我们重点关注两点,这个在Handler的原理分析中会做详细的说明:

  • Looper.prepareMainLooper();
  • Looper.loop();

Handler的预备分析

一、 首先程序在启动的时候,会执行ActivityThread类的main方法,如上我们提到两个重要的代码: Looper.prepareMainLooper();

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

  在他的prepare方法中,创建了一个Looper,并把它放在了ThreadLocal中:

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

二、 ActivityThread中的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.recycleUnchecked();
}
}

  在msg.target.dispatchMessage(msg);方法中msg.target这是分发消息的Handler

public void dispatchMessage(Message msg) {
if (msg.callback != null) {
     // 首先,处理Message自己的callback,调用其run方法
handleCallback(msg);
} else {
if (mCallback != null) {
       // 其次,调用Handler自留的接口对象
if (mCallback.handleMessage(msg)) {
return;
}
}
     // 最后,调用handleMessage方法处理消息,Handler类中这个方法为空,子类可以重写这个方法
handleMessage(msg);
}
}

Handler的原理分析

我们仍旧用一个例子来加以说明Handler的原理,例子代码具体可以参见我的博客:(android基础---->子线程更新UI)。以下的分析我会帖出有关例子的重要代码:

一、 创建一个Handler,处理消息:

public static final int UPDATE_TEXT = 1;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_TEXT:
textView.setText("I Love you.");
break;
default:
break;
}
}
}

二、 发送消息:

// 用handler处理上述问题
public void handlerUpdate(View view) {
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message); // 将Message对象发送出去
}
}).start();
}

三、 首先我们要创建一个handler,具体构造方法代码如下,这里由于是new Handler():callback=null,async=false

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

四、 接下来进行了我们消息的发送:handler.sendMessage(message),源代码如下:(中间我们省略了一些过程)

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);
}
  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);
}
  • 所谓发送消息就是把消息放入消息队列中的合适位置,并且把消息的target设置为本Handler对象。

五、 在上述Handler的预备分析当中,我们提到过Looper的loop方法,它负责从队列中取出消息,并且分发消息。

而且我们在Handler的dispatchMessage方法也了解到,分发的消息会由Handler的handleMessage方法处理:也就是我们创建的Handler的重写方法:

public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_TEXT:
textView.setText("I Love you.");
break;
default:
break;
}
}
  • 当队列中的消息处理的时候,也会找到当时送它来的Handler对象,
  • 调用其相应的dispatchMessage()方法
  • 调用其中的handleMessage()方法或者mCallback成员的handleMessage()方法来进行处理。

友情链接