什么是Handler
我们来看一下Handler源码中是怎么说的
/**
* A Handler allows you to send and process {@link Message} and Runnable
* objects associated with a thread's {@link MessageQueue}. Each Handler
* instance is associated with a single thread and that thread's message
* queue. When you create a new Handler, it is bound to the thread /
* message queue of the thread that is creating it -- from that point on,
* it will deliver messages and runnables to that message queue and execute
* them as they come out of the message queue.
* Handler 允许您发送和处理{@链接消息}和与一个线程的{@ Link MessageQueue}}相关联的Runnable对象。每个Handler
* 实例与单个线程和该线程的消息队列关联。当创建新的 Handler 时,它将绑定到线程和该线程正在创建线程的消息队列。
* 从那时起,当它们从消息队列中出来时,Handler将向该消息队列(message queue)传递messages and runnables并执行。
*
* <p>There are two main uses for a Handler: (1) to schedule messages and
* runnables to be executed as some point in the future; and (2) to enqueue
* an action to be performed on a different thread than your own.
* 处理程序有两个主要用途:
* (1)调度消息和将来执行某个点的runnables;
* (2)入队在一个不同的线程上执行的动作。
*
* <p>Scheduling messages is accomplished with the
* {@link #post}, {@link #postAtTime(Runnable, long)},
* {@link #postDelayed}, {@link #sendEmptyMessage},
* {@link #sendMessage}, {@link #sendMessageAtTime}, and
* {@link #sendMessageDelayed} methods.
* The <em>post</em> versions allow you to enqueue Runnable objects to be called by the message queue when they are received;
* the <em>sendMessage</em> versions allow you to enqueue a {@link Message} object containing a bundle of data that will be
* processed by the Handler's {@link #handleMessage} method (requiring that
* you implement a subclass of Handler).
* 消息调度是通过#post#postDelayed#sendMessage#sendMessageDelayed这4个方法完成的。
* post版本的方法允许你接收消息队列时调用的可运行对象的队列;
* sendMessage版本的方法允许你调用一个包含bundle数据队列,这个bundler数据最终会被Handler子类的handleMessage方法所处理
*
* <p>When posting or sending to a Handler, you can either
* allow the item to be processed as soon as the message queue is ready
* to do so, or specify a delay before it gets processed or absolute time for
* it to be processed. The latter two allow you to implement timeouts,
* ticks, and other timing-based behavior.
* 当发送到Handler,您可以当消息队列准备就绪时,允许处理该项。或者在它被处理之前或者在绝对时间之前指定一个延迟。
* 后两者允许您实现超时、记号、和其他基于时间的行为。
*
* <p>When a
* process is created for your application, its main thread is dedicated to
* running a message queue that takes care of managing the top-level
* application objects (activities, broadcast receivers, etc) and any windows
* they create. You can create your own threads, and communicate back with
* the main application thread through a Handler. This is done by calling
* the same <em>post</em> or <em>sendMessage</em> methods as before, but from
* your new thread. The given Runnable or Message will then be scheduled
* in the Handler's message queue and processed when appropriate.
* 当为应用程序创建进程时,其主线程专用于运行管理顶级队列的消息队列应用对象(活动、广播接收器等)和他们创造的任何窗口。
* 您可以创建自己的线程,并通过Handler与主线程与之通信。这是在你新的线程里面通过调用相同的POST或sendMessage方法来完成的。
* 然后,给定的可运行或消息将被安排在处理程序的消息队列中,并在适当的时候进行处理。
*/
先看一个Handler的应用例子,在一个服务中,发送消息给activity
handler在activity中定义
public class MainActivity extends AppCompatActivity {
private static DemoHandler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (handler == null) {
handler = new DemoHandler();
}
}
public class DemoHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
//透传
startActivity(new Intent(MainActivity.this, ScannerActivity.class));
break;
case 1:
//推送
startActivity(new Intent(MainActivity.this, ScannerActivity.class));
break;
}
}
}
public static void sendMessage(Message msg) {
handler.sendMessage(msg);
}
}
service发送消息:
public class GeTuiIntentService extends GTIntentService {
@Override
public void onReceiveMessageData(Context context, GTTransmitMessage gtTransmitMessage) {
//收到透传消息
String data = new String(gtTransmitMessage.getPayload());
sendMessage(data,0);
}
private void sendMessage(String data, int what) {
Message msg = Message.obtain();
msg.what = what;
msg.obj = data;
MainActivity.sendMessage(msg);
}
}
这是我们常见的一种Handler使用方式,sendMessage(msg);
这样我们就简单实现了service和activity之间的通信。
那具体Handler是怎么工作的呢?我们先看一下在执行 new Handler()的时候,查看Handler类,都做了那些工作:
public Handler() {
this(null, 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());
}
}
//获取一个Looper对象
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//获取Looper中的消息队列
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
由上可以看出,在我们初始化Handler的时候,做了两步工作,获取Looper和MessageQueue两个对象。
那我们在发送消息的时候,又做了哪些工作呢?
Message msg = Message.obtain();
msg.what = what;
msg.obj = data;
MainActivity.sendMessage(msg);
查看Message类:
private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
private static boolean gCheckRecycle = true;
/**
* 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;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
创建一个message对象,如果sPool!=null时,返回已有message对象。返回对象之后,给message的what和obj参数赋值。
这两个参数啥意思啊?请看源码解释:
/**
* User-defined message code so that the recipient can identify
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
*/
//用户自己定义的消息码,以便接收方可以识别该消息是关于什么的。每一个Handler都有它自己消息码的名称空间,因此你不必担心与其他Handler发生冲突。
public int what;
/**
* An arbitrary object to send to the recipient. When using
* {@link Messenger} to send the message across processes this can only
* be non-null if it contains a Parcelable of a framework class (not one
* implemented by the application). For other data transfer use
* {@link #setData}.
*
* <p>Note that Parcelable objects here are not supported prior to
* the {@link android.os.Build.VERSION_CODES#FROYO} release.
*/
//要发送给接收者的任意对象。当使用Messenger跨进程发送消息时,如果它包含一个序列化的framework class,这个对象不能为空
public Object obj;
说白了,一个是消息码,一个是消息,消息码来标记消息是干嘛用的。
继续看 handler.sendMessage(msg);方法,大概意思是把一个消息推到消息队列的尾部,这个消息会在连接到这个Handler的线程中的handleMessage方法中接收到。
/**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
传入当前消息、消息所在消息队列、uptimeMillis,到enqueueMessage()
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; 目的是给msg绑定Handler
这时候,msg中已经赋值对象有:what(标记)、obj(数据)、target(Handler)
最后执行消息队列MessageQueue中的 enqueueMessage方法,传入msg。
boolean enqueueMessage(Message msg, long when) {
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(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
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.
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在创建的时候,初始化了一个Looper,那么Looper里面做了哪些工作呢?
/**
* 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.loop()进入循环模式,知道msg==null,退出循环。注意中间的 msg.target.dispatchMessage(msg); 方法。调用的是Handler的dispatchMessage(msg);方法,传入消息。
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
在handleMessage方法汇总处理消息!
至此,一个完整的消息处理流程已经梳理完毕。
总结一下:
一个完整的Handler消息处理一共涉及4个类:
Handler:消息辅助类,主要功能是向消息池发送消息事件(4种发送方式),和处理相应消息事件handleMessage。
Message:消息载体类,主要参数有消息码、消息内容、绑定Handler
MessageQueue:消息队列,主要向消息池投递消息(MessageQueue.enqueueMessage)和取走消息(MessageQueue.next)。
Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者。
Handler通过sendMessage()发送Message到MessageQueue队列;
Looper通过loop(),不断提取出达到触发条件的Message,并将Message交给target来处理;
经过dispatchMessage()后,交回给Handler的handleMessage()来进行相应地处理。
将Message加入MessageQueue时,处往管道写入字符,可以会唤醒loop线程;如果MessageQueue中没有Message,并处于Idle状态,则会执行IdelHandler接口中的方法,往往用于做一些清理性地工作。
tip:为啥:主线程中创建Handler不需要调用Looper.prepare();和Looper.loop();方法;而在子线程中创建Handler需要调用这两个方法呢?
细心的你可能会发现,在Looper类的源码中,给我们提供了一个使用这两个方法创建Handler的例子:
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();
}
}
而我们给出的在主线程中的例子没有这两个方法,也许我们可以去看一下主线程的源码来查一下其中的原因。找到ActivityThread.java源码:找到main函数:
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");
}
/**
* 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();
}
}
这下明白了,主线程汇总已经调用了这两个方法!
Looper类用来为一个线程开启一个消息循环。
默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)
Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。
扫码关注,共同进步