Android Handler消息机制解析
Android Handler消息机制解析
众所周知 Handler在Android中的地位非常重要, 从处理异步线程任务队列的HandlerThread到从子线程与UI线程的通信, 再到ActivityThread中四大组件的sendMessage调度, 再到进程间通信与之关联Messenger 可以说是从头到尾贯穿的整个Android系统的枝枝蔓蔓。 所以说搞明白,搞懂Handler消息运行机制与原理至关重要。由于Handler消息机制使用的地方非常之广泛,类中的内容可能关联的比较多,所以本文只侧重于对与Handler消息机制关联的重要部分进行分析。
在进行分析之前我们先分析几个问题,
- 1. 为什么要有Android消息机制?
- 2. 子线程是如何通过Handler与UI线程通信的?
- 3. UI线程中的Handler又是如何和UI线程绑定的?
- 4. Handler是如何收发消息的?
- 5. 一个Handler线程中可以关联多个Handler吗?
- 6. 常用Handler消息机制组件有哪些?
我会从以下六个方面全方位解析Handler消息机制,并解释以上几个相关问题。
为什么要有Android消息机制?
我们知道Handler的主要作用是将一个任务切换到某个指定的线程去执行,比如Android规定访问UI只能在主线程中进行,在大多数情况下如果在子线程中访问那么程序会抛异常。
void checkThread(){
if(mThread != Thread.currentThread()){
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
当然也有一些特殊情况,比如ProgressBar 的setProgress就可以在子线程中更新,而不会crash。 但是如果继续细细深究,查找代码会发现,ProgressBar已经帮我们做了处理, 非UI线程的时候,会把refreshProgress 操作放入post中,通过Handler机制进行更新了。
为什么系统不允许在子线程中访问UI呢?
这是因为Android的UI控件不是线程安全的,如果在多线程中访问UI控件则会导致不可预期的状态。那为什么不对UI控件访问加锁呢?缺点有两个:首先加锁会让UI控件的访问的逻辑变的复杂;其次,锁机制会降低UI的访问效率。那我们不用线程来操作不就行了吗?但这是不可能的,因为Android的主线程不能执行耗时操作,否则会出现ANR。所以,从各方面来说,Android消息机制是为了解决在子线程中无法访问UI的矛盾。
Looper类基本解析
打开Looper 就有这么一段注释, 就是解释了Looper的简单实用方法。如下代码:
This is a typical example of the implementation of a Looper thread,
using the separation of {@link #prepare} and {@link #loop} to create an
initial Handler to communicate with the Looper.
<pre>
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
<!--prepare-->
Looper.prepare();
<!-- new Handler-->
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
<!--loop-->
Looper.loop();
}
}</pre>
说到Looper类, 主要有三个部分需要注意, 1.Looper 类中的prepare方法, prepareMainLooper方法; 2.Looper类中的MessageQueue对象的轮询 也就是loop方法; 3. ThreadLocal与Looper和Thread关联状态
下边说第一个部分 , Looper类中的prepare方法, 敲黑板 这一部分很重要
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Printer mLogging;
private long mTraceTag;
/* If set, the looper will show a warning log if a message dispatch takes longer than time. */
private long mSlowDispatchThresholdMs;
/** 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) {
throw new RuntimeException("Only one Looper may be created per thread");
}
///Looper对象通过 ThreadLcoal 与本地的Thread 对象进行了关联。
sThreadLocal.set(new Looper(quitAllowed));
}
/**
* 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 方法,只是不允许quit , 这是肯定了, UI线程岂是能随便quit的。
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;
}
}
看到prepare 方法 就能够理解了,Looper是如何与当前线程进行绑定的。 如果知道详细的绑定过程和原理 请看我的另一篇文章ThreadLocal 源码详细解析, 那这里就不再赘述了。
再说第二部分: Looper类中的MessageQueue对象的轮询也就是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) {
// 当一个线程没有prepare 直接loop的话就会报这个异常。
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 获取到当前Looper对象引用的Queue
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();
}
}
Message类基本解析
既然谈的是线程间通信,则肯定少不了信, 也就是Message, 说到Message则与本文相关联需要关注的地方有两个: 1. Message中的相关字段。 2. Message 中的 sPool 以及obtain方法。
Message中的相关字段
/**
* 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.
* 该字段一般标志消息的类型,以及分类。 大部分情况作为处理消息的类型来判断。
*/
public int what;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
* arg1 and arg2 这是个低消耗的,轻量级的消息数据传递类型。
*/
public int arg1;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg2;
/**
* 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.
* 传递Object类型, 注意Parcelable对象是从FROYO版本以后才开始支持的
*/
public Object obj;
obtain方法
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
* 这里边维护了一个单链表, Message 内部有next 字段, 指向下一个节点, 这样也有利于循环利用。
*/
public static Message obtain() {
// 添加线程锁
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
/// message.next -->>> sPool 指定给头节点
sPool = m.next;
m.next = null;
/// message.next =null;
m.flags = 0; // clear in-use flag
sPoolSize--;
/// size -- , 返回 并重新利用
return m;
}
}
return new Message();
}
/**
* Same as {@link #obtain()}, but copies the values of an existing
* message (including its target) into the new one.
* @param orig Original message to copy.
* @return A Message object from the global pool.
* 这个和obtain()方法一样,但是这个是利用了recycle pool生成的Message ,是根据传入的Message 完全copy的。
*/
public static Message obtain(Message orig) {
// 一一拷贝字段
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
m.sendingUid = orig.sendingUid;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}
MessageQueue类基本解析
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;
}
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) {
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 (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
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(TAG, "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;
}
}
Handler类基本解析
/**
* 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) {
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;
}
/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also 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 looper The looper, must not be null.
* @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(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @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. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
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);
}
/**
* Enqueue a message at the front of the message queue, to be processed on
* the next iteration of the message loop. You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
* <b>This method is only for use in very special circumstances -- it
* can easily starve the message queue, cause ordering problems, or have
* other unexpected side-effects.</b>
*
* @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 sendMessageAtFrontOfQueue(Message msg) {
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, 0);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*/
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public boolean handleMessage(Message 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);
}
}
常见应用
上边聊了那么多, 看一下实际的应用,下边举了三个栗子, 一起来看一下好不好吃。
HandlerThread
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
* prepare完成之后,会调用该方法, 通过该方法的回调,初始化该线程的Handler.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
//这里防止线程没有启动,等待线程启动,并且Looper已经创建好了。
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
/// 返回当前线程的Looper
return mLooper;
}
IntentService
IntentService 可以放置在后台跑一个工作线程,用来执行耗时任务, 使用方法就不再多说了, 下边我们看一下实现, 其中工作机制和Handler 消息机制的关联。 IntentService类的代码也没多少,干脆直接全部粘贴出来好了。
/**
* IntentService is a base class for {@link Service}s that handle asynchronous
* requests (expressed as {@link Intent}s) on demand. Clients send requests
* through {@link android.content.Context#startService(Intent)} calls; the
* service is started as needed, handles each Intent in turn using a worker
* thread, and stops itself when it runs out of work.
*
* <p>This "work queue processor" pattern is commonly used to offload tasks
* from an application's main thread. The IntentService class exists to
* simplify this pattern and take care of the mechanics. To use it, extend
* IntentService and implement {@link #onHandleIntent(Intent)}. IntentService
* will receive the Intents, launch a worker thread, and stop the service as
* appropriate.
*
* <p>All requests are handled on a single worker thread -- they may take as
* long as necessary (and will not block the application's main loop), but
* only one request will be processed at a time.
*
* <p class="note"><b>Note:</b> IntentService is subject to all the
* <a href="/preview/features/background.html">background execution limits</a>
* imposed with Android 8.0 (API level 26). In most cases, you are better off
* using {@link android.support.v4.app.JobIntentService}, which uses jobs
* instead of services when running on Android 8.0 or higher.
* </p>
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For a detailed discussion about how to create services, read the
* <a href="{@docRoot}guide/components/services.html">Services</a> developer
* guide.</p>
* </div>
*
* @see android.support.v4.app.JobIntentService
* @see android.os.AsyncTask
*/
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
/// 收到消息后就在这里处理了,然后会回调onHandleIntent这个方法, 由于这里的Handler里引用的Looper是在HandlerThread中的,所以可以看到这里是可以执行耗时操作的。
onHandleIntent((Intent)msg.obj);
// 执行完毕之后,就把Service停止了。
stopSelf(msg.arg1);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* Sets intent redelivery preferences. Usually called from the constructor
* with your preferred semantics.
*
* <p>If enabled is true,
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_REDELIVER_INTENT}, so if this process dies before
* {@link #onHandleIntent(Intent)} returns, the process will be restarted
* and the intent redelivered. If multiple Intents have been sent, only
* the most recent one is guaranteed to be redelivered.
*
* <p>If enabled is false (the default),
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
* dies along with it.
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
/// 这里边引用的是HandlerThread,获取HandlerThread 中的Looper ,用线程中的Looper 来初始化ServiceHandler。
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
/// 看到了吧, 当service 销毁时,会调用Looper 的quit 方法, 也就是中断了Loop里边的死循环。handlerThread自然就停止了
mServiceLooper.quit();
}
/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
* 如果使用IntentService 需要继承该方法, 具体的耗时操作就放在这里边。任务执行完毕,就会看到 会调用stopSelf 方法, 调用者不用担心Service不会关闭而造成资源浪费。
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
通过onStartCommand方法和handlemessage看到 ,如果同一个Service 启动多次, 则会把Intent分批次传递给onHandleIntent方法中, 也就是HandlerThread中顺序执行完成。就说到这, 我们看下个栗子。
主程序入口
public static void main(String[] args) {
...
//这个地方就是创建一个Looper,并且放在ThreadLocal里。prepareMainLooper
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);
// Loop.loop()根据上边对loop的解析,我们知道这是一个死循环,但是在没有消息的时候会堵塞
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
看到了应用的主要入口, main(String[] args) 方法, 这里就是UI线程的入口, 也是MainThreadHandler的声明地方,也是把Looper和UI线程关联的地方。
从这一点来讲,也就解释了,为什么在Activity中声明的一个普通handler字段 发消息却能够在UI线程处理了。 因为这个Handler 内部引用的Looper是与主线程的关联的Looper, 所以这个Handler也就是属于主线程的Handler , 同时也说明了为什么引用Handler字段能够在子线程中给主线程发消息。还是因为这个Handler内部引用的Looper是MainThreadLooper。
/**
* 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;
}
}
boolean quitAllowed = false; 也就是不允许手工终止的, 仔细考虑一下也就是这样的, 一个系统的设计,无论从什么角度来考虑,主线程的消息处理是无法被中断的。
从另一个角度讲如果想让Application 退出是不是将loop的这个循环终止就行了?
摘自ActivityThread中的一段代码。
case EXIT_APPLICATION:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
/// loop.quit , 退出应用,实际上就是退出了loop, 我靠,好精妙绝伦的设计。 niubility
Looper.myLooper().quit();
break;
既然说到了这里 ,就简单聊一下主线程中的Handler 在ActivityThread中的作用,what? 没用, 开玩笑的. 来先粘一小段代码压压惊。
// 这个handler 在主线程中的形态是这样的,一个静态的,具有原子性的,UI线程中的非常繁忙的Handler。
static volatile Handler sMainThreadHandler; // set once in main()
//初始化是在下边这一行
/// sMainThreadHandler = thread.getHandler();
final Handler getHandler() {
return mH;
}
final Looper mLooper = Looper.myLooper();
final H mH = new H();
//在ActivityThread 中发送消息,处理消息的Handler 也就是这个H ,
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
public static final int HIDE_WINDOW = 106;
public static final int RESUME_ACTIVITY = 107;
public static final int SEND_RESULT = 108;
public static final int DESTROY_ACTIVITY = 109;
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int NEW_INTENT = 112;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public st![image](https://note.youdao.com/favicon.ico)![image](https://note.youdao.com/favicon.ico)![image](https://note.youdao.com/favicon.ico)atic final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;
public static final int CONFIGURATION_CHANGED = 118;
public static final int CLEAN_UP_CONTEXT = 119;
public static final int GC_WHEN_IDLE = 120;
public static final int BIND_SERVICE = 121;
public static final int UNBIND_SERVICE = 122;
public static final int DUMP_SERVICE = 123;
public static final int LOW_MEMORY = 124;
public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
public static final int RELAUNCH_ACTIVITY = 126;
public static final int PROFILER_CONTROL = 127;
public static final int CREATE_BACKUP_AGENT = 128;
public static final int DESTROY_BACKUP_AGENT = 129;
public static final int SUICIDE = 130;
public static final int REMOVE_PROVIDER = 131;
public static final int ENABLE_JIT = 132;
public static final int DISPATCH_PACKAGE_BROADCAST = 133;
public static final int SCHEDULE_CRASH = 134;
public static final int DUMP_HEAP = 135;
public static final int DUMP_ACTIVITY = 136;
public static final int SLEEPING = 137;
public static final int SET_CORE_SETTINGS = 138;
public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
public static final int TRIM_MEMORY = 140;
public static final int DUMP_PROVIDER = 141;
public static final int UNSTABLE_PROVIDER_DIED = 142;
public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
public static final int INSTALL_PROVIDER = 145;
public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
public static final int ENTER_ANIMATION_COMPLETE = 149;
public static final int START_BINDER_TRACKING = 150;
public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
public static final int MULTI_WINDOW_MODE_CHANGED = 152;
public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
public static final int ATTACH_AGENT = 155;
public static final int APPLICATION_INFO_CHANGED = 156;
public static final int ACTIVITY_MOVED_TO_DISPLAY = 157;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
/// .... 这里就省了
}
}
return Integer.toString(code);
}
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case PAUSE_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, args.argi3);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case PAUSE_ACTIVITY_FINISHING: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, true, (args.argi1 & USER_LEAVING) != 0,
args.argi2, (args.argi1 & DONT_REPORT) != 0, args.argi3);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case STOP_ACTIVITY_SHOW: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
SomeArgs args = (SomeArgs) msg.obj;
handleStopActivity((IBinder) args.arg1, true, args.argi2, args.argi3);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case STOP_ACTIVITY_HIDE: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
SomeArgs args = (SomeArgs) msg.obj;
handleStopActivity((IBinder) args.arg1, false, args.argi2, args.argi3);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case SHOW_WINDOW:{
} break;
}
}
简单看了H这个类, 继承自Handler , 初始化是在ActivityThread 类中以普通私有变量的方式声明。 可能会有这样的疑问, 类的main方法还没执行哪儿来的Looper来让handler 引用? 别忘了 Java 中类中的字段初始化顺序和执行顺序了, 1. 先初始化话静态变量, 2. 初始化构造函数 ,3.初始化非静态变量,执行顺序是从上到下。 4. 执行 static main 方法。 看一下源码 Looper mlooper = Looper.myLooper(); 在Handler mH 上边的, 也就是说在Handler初始化的时候, Looper已经和当前UI 线程通过ThreadLocal进行绑定了。 然后再从getHandler方法对mHandler 初始化。
看了上边的一坨代码, 了解到
LAUNCH_ACTIVITY , PAUSE_ACTIVITY ,PAUSE_ACTIVITY_FINISHING, STOP_ACTIVITY_SHOW ,STOP_ACTIVITY_HIDE ,SHOW_WINDOW , HIDE_WINDOW , 等等这么N多的消息类型的发送以及处理都是这个H处理, 看到了如此操心的小H , 不禁地感慨道当26个字母中最不容易的也就是你了啊兄弟。
总结
上边分析了那么多, 看了那么一大堆的代码,我们清楚的了解到了Handler机制对于Android系统的重要性。所以也有人说Handler消息机制是FrameWork层的发动机,这么考虑一下一点也不为过吧。 由于个人能力和理解范围的限制,文中难免有错误,欢迎大家拍砖批评指正。
上一篇: Handler传递对象