1、Handler简介
Handler是Android的一种消息机制,用于同一进程的线程间通信,在这里引用一些任老师书里的描述。 Handler的主要作用是将一个任务切换到某个指定的线程中去执行。那么Android为什么要提供这个功能呢?那是因为Android规定访问UI只 能在主线程中进行,如果再子线程中访问UI,那么程序就会抛出异常(这个验证是否是主线程的工作在ViewRootImpl的checkThread方 法里完成)。这里说的主线程比较特殊,它是由Zygote fork创建的进程,程序入口是ActivityThread类的main方法,然而AcitvityThread不是一个Thread,只是一个final类,后面会有进一步说明。
void checkThread(){
if(mThread != Thread.currentThread){
throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views");
}
}
为什么系统不允许子线程访问UI呢?那是因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可 预期的状态。那为什么系统不对UI控件的访问加上锁机制呢?有两个原因,首先加上锁机制会让UI访问的逻辑变得复杂;其次锁机制会降低UI访问的效率(例 如阻塞某些线程的执行)。因此最简单且高效的就是采用单线程模型来处理UI操作,这个单线程就是主线程,而开发者只需通过Handler机制切换到主线程 中去执行UI操作。例如,我们都知道的一个著名错误ANR,Android建议不要在主线程中进行耗时操作,否则会导致ANR,因此一般都会拉起一个线程来执行耗时操作,而这个耗时操作完后又要反映到UI的变化,此时我们就要用Handler,将UI的变化工作切换到主线程中去执行。最后,Android之所以提供 Handler,主要原因就是为了解决在子线程中无法访问UI的矛盾,而Handler并不是专门用于更新UI(例如HandlerThread的应用),它只 是常被开发者用来更新UI。
2、Handler机制梳理
平常我们说的Handler,指的是由Handler、Message、MessageQueue和Looper构成的一个整体运行机制。我们可以从下图,大概了解它们的运行流程。![](https://i-blog.csdnimg.cn/blog_migrate/d636e49d2e113ea52c80266592154bd0.png)
首先就是Handler调用sendXXX系列或者postXXX系列的方法发送Message,不管是哪种方法都是需要从全局消息池里面拿出一个Message对象,即obtain(虽然Message有个全局消息池,其实它的内部实现只是一个对链头进行插入和删除的单链表,毕竟单链表在插入和删除上比较有优势),接着对该Message对象进行各种成员变量的赋值后,把它发送到相应线程的消息队列中,即enqueueMessage(虽然MessageQueue叫消息队列,但它的内部实现并不是队列,和全局消息池一样,也是一个对链头进行插入和删除的单链表),之后的工作交给相应线程的Looper对象,它通过调用loop()方法,无限循环地往消息队列里取消息,即next(),如果队列里无消息,它便被阻塞了(nativePollOnce和nativeWake,本地方法使用Linux的epoll模型)。如果有消息便把消息取出来,同时消息队列伴随着删除该消息的操作,然后调用Message对象的target成员变量的dispatchMessage方法进行消息分发处理,target实际上就是Handler的实例。Handler把消息处理完后,Looper便要把这条消息进行回收再利用,即recycle(),对消息进行“净身”,即置空消息的所有成员变量,之后保证消息无污染地插入全局消息池中,避免OOM。
3、Handler机制分析
大家读到这里有没有产生这样的疑问,上面提到相应线程的消息队列和相应线程的Looper对象,Handler发送消息它是怎么识别发送到哪个线程中的消息队列呢?下面我写了个小例子,我们跟着代码分析。public class TestHandler extends Handler {
public static final String TAG = "TestHanlder";
private String mName = null;
public TestHandler(String n) {
// TODO Auto-generated constructor stub
mName = n;
}
public TestHandler(String n, Looper lp){
super(lp);
mName = n;
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch(msg.what){
case 1:
Log.d(TAG, mName);
break;
default:
break;
}
}
}
这里我写的一个比较简单的继承于Handler的TestHandler类,接下来在界面xml里声明一个button,在mainActivity对这个button的点击事件进行处理,处理里new一个TestHandler对象并发送消息。
public void button1(View v){
TestHandler th = new TestHandler("button1");
Log.d(TAG,th.getLooper().getThread().toString());
th.sendEmptyMessage(1);
}
点击按钮后打印信息如下:
09-17 17:17:09.879: D/MainActivity(21186): Thread[main,5,main]
09-17 17:17:09.879: D/TestHanlder(21186): button1
这里new一个TestHandler实例后,我打印出与该实例所绑定的线程名称,通过log可看成,这个线程是主线程,接着后面的sendEmptyMessage方法就是把消息发送给主线程的,问题来了,TestHandler是怎么知道要把消息发送给主线程的。我们可以看看TestHandler的构造方法,虽然方法里只是简单的对mName进行赋值,但它隐藏了一个段代码,即隐式地调用了父类的构造方法super()。TestHandler的父类是Handler,接下我们看看Handler源码,它的构造方法里都做了什么。
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
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());
}
}
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类有两个成员变量mLooper和mQueue,它们代表着TestHandler消息发往的消息队列和循环消息处理的Looper。其中mQueue是mLooper的成员变量,姑且不管,我们看看mLooper是怎么赋值的。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
final MessageQueue mQueue;
... ... ...
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
这里涉及到一个ThreadLocal类,相关使用和原理大家可以去搜索了解一下。简单说,这里ThreadLocal<Looper>就是类似于Map<Key,Value>,其中Key是线程对象,而Value就是Looper对象。这里sThreadLocal.get(),Key就是当前线程,该方法返回当前线程对应的Looper对象。当然如果当前线程没有Looper对象,Handler就会抛出异常,也就是我们常见“Can't create handler inside thread that has not called Looper.prepare()”。话说回来了,new一个TestHandler实例时候是在MainActivity里,当前线程当然是主线程,于是这个TestHandler在构造时就与主线程的Looper和MessageQueue绑定了,只要其他线程能获取该TestHandler实例来发送消息,消息便能发送到主线程的队列里,从而促发主线程的Looper调用Handler处理消息,这就是切换到主线程进行UI操作,而TestHandler类,如其名Handler——处理者,里面实际就包含了你自己写的,要做什么UI的处理操作,这里只是简单的一句log打印。这里留一个疑问,上面说过,如果当前线程没有Looper对象,Handler就会抛出异常,那么主线程是什么时候拥有Looper对象的?这个问题和开篇说的ActivityThread有关系,后面说。
从上面我可以知道,Looper不断循环取消息并处理,其中处理操作其实就是调用了Handler的dispatchMessage方法,由Handler进行消息分发处理,我们看看Handler分发消息的实现:
/**
* 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);
}
}
既然Handler对消息进行分发处理,那么都有哪些处理者接受Handler的分发呢?从上面代码中看到,有三个处理者,分别是msg.callback、mCallback和handleMessage()。首先msg.callback是什么,接着看Handler源码:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
... ... ...
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
private static void handleCallback(Message message) {
message.callback.run();
}
看上面我粘贴的部分关键源码可知,msg.callback就是postXXX系列方法传入进来的Runnable对象,消息处理在该对象的run方法里进行。接着我们看第二位处理者mCallback,在Handler源码里:
/**
* 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(Callback callback) {
this(callback, 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);
}
... ... ...
final Callback mCallback;
由此可知,mCallback是Callback接口,需要实现它的handleMessage方法来处理消息,它的存在就是为我们提供另一种使用Handler的方式,如注释说的创建一个Handler实例但并不需要派生Handler子类。剩下的第三位处理者就是继承Handler并重写handleMessage方法的子类对象,也是我们平常用的较多的,就像上面例子中的Testhandler一样,继承了Hnadler,重写了handleMessage方法,方法里打印了button1。
接下来我们可以看看非主线程是如何具有Handler机制,还是例子分析,和上面工程一样,只是添加了个button2按钮和一个TestHandlerThreadHelp类,首先我们看button2的调用代码,如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TestHanlderThreadHelp.getInstance().starTest("MyTestHandler");
}
public void button2(View v){
TestHandler th = TestHanlderThreadHelp.getInstance().getHandlerInMyThread("button2");
Log.d(TAG,th.getLooper().getThread().toString());
th.sendEmptyMessage(1);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
TestHanlderThreadHelp.getInstance().stopTest();
}
TestHandlerThreadHelp类实现了单例模式,它有一个内部线程类TestHandlerThread,这里的getHandlerInMyThread方法是获取一个与TestHandlerThread线程绑定了的Handler实例对象,然后在主线程里发送消息,在TestHandlerThread线程里进行消息处理。在mainActivity的onCreate()方法里startTest(),里面新建一个TestHandlerThread对象,然后start()开启线程跑起来。在onDestroy()方法里stopTest(),做一些释放工作。接下来看看TestHandlerThreadHelp的实现:
public class TestHanlderThreadHelp {
public static final String TAG = "TestHanlderThreadHelp";
private TestHanlderThread mtht = null;
private TestHandler th = null;
private TestHanlderThreadHelp() {
}
private static class TestHanlderThreadHelpHolder {
private static final TestHanlderThreadHelp mInstance = new TestHanlderThreadHelp();
}
public static TestHanlderThreadHelp getInstance(){
return TestHanlderThreadHelpHolder.mInstance;
}
public TestHandler getHandlerInMyThread(String n){
if(th == null)
th = new TestHandler(n,mtht.getLooper());
return th;
}
public void starTest(String threadName){
if(mtht == null)
mtht = new TestHanlderThread(threadName);
mtht.start();
}
public void stopTest(){
if(mtht != null)mtht.quit();
mtht = null;
th = null;
}
private class TestHanlderThread extends Thread{
Looper mLooper;
public TestHanlderThread(String threadName) {
// TODO Auto-generated constructor stub
super(threadName);
}
@Override
public void run() {
// TODO Auto-generated method stub
//super.run();
Looper.prepare();
mLooper = Looper.myLooper();
Looper.loop();
}
public Looper getLooper(){
if(!isAlive())
return null;
return mLooper;
}
public boolean quit(){
Looper lp = getLooper();
if(lp != null){
lp.quit();
return true;
}
return false;
}
}
}
点击按钮后打印的log信息:
09-18 10:34:37.689: D/MainActivity(21695): Thread[MyTestHandler,5,main]
09-18 10:34:37.699: D/TestHanlder(21838): button2
这里我们看到打印出来与TestHandler实例绑定的线程名称,就是我们new一个TestHandlerThread线程对象时的传入名称MyTestHandler,button2的打印就在MyTestHandler线程里执行的。从之前Handler运行流程图,我们知道一个独立的线程要具有Handler处理机制,那么它就要有自己的消息队列并且有Looper在循环处理。这也就是TestHandlerThread的run方法里面要做的工作,对应分别是Looper.prepare()和Looper.loop(),它们是必须的。接下来我们看看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) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
... ... ...
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper.prepare()工作就是,如果当前线程没有Looper对象的话,就为当前线程new一个Looper对象,这里的sThreadLocal.set方法,简单理解就是保存一个键值对,key是当前线程对象,value是new出来的Looper对象。和它相反的之前提过的,就是sThreadLocal.get(),在Looper.myLooper()方法里,表示取出key是当前线程的Looper对象。而在Looper的构造函数里,new了一个属于该Looper对象的MessageQueue对象,也就是说,Looper对象与MessageQueue对象绑定了,只要获取相应线程的Looper对象,就能获取Looper对象对应的消息队列。最后就是Looper.loop()了,里面代码太长就不贴上来了,这个方法可以简单理解为,它从消息队列里取一个消息并处理,完后再取下一个消息再处理,周而复始地工作,如果消息队列里无消息了,它就会被阻塞了,释放资源进行休眠,一旦有消息来了就要被唤醒并重新开始工作,除了主线程外,loop是可以退出的,而退出死循环的方法就是取消息的next()返回空,除了主线程的Looper外,其他线程的Looper都可以 通过quit方法进行退出,TestHandlerThread类里面提供的退出loop的方法就是调用了Looper的quit方法,它的实现很简单,就是调用MessageQueue的quit方法,从而使得MessageQueue的next()方法返回空,这时候loop()方法的死循环就跳出来了,从而线程运行结束并销毁。运行这两个方法之后,我们的MyTestHandler线程就是一个具有Handler消息处理机制的线程了。
然而这里还是有问题的,问题是我们怎么把消息发到MyTestHandler线程的消息队列里呢?也就是说,我们在new一个Handler实例时怎么绑定MyTestHandler线程对应的Looper对象呢?于是TestHandlerThread类里就有了一个mLooper成员变量及其getter方法,用于存储和获取TestHandlerThread线程对应的Looper对象。在new一个Handler实例时,Hanlder有一个构造方法Handler(Looper),作用就是把Handler实例就与传入的Looper对象绑定在一起了,此后它的发送消息就会发到与这个Looper对象对应的线程里。因此在程序里,我写了个包装了TestHandlerThread类的TestHandlerThreadHelp类,它的getHandlerInMyThread方法里就返回了绑定了TestHandlerThread线程的Handler实例。至此,其他线程只要拿到这个实例,就能往TestHandlerThread线程发送消息了。因此,我们在mainActivity的button2方法里,调用TestHandlerThreadHelp类的getHandlerInMyThread方法获取Handler实例并发送消息,效果等于在主线程里往MyTestHandler线程发送消息,最后在MyTestHandler线程里处理消息。这里写的TestHandlerThread类仅仅为了测试验证所写,实际使用中,还是推荐使用android系统现成提供的HandlerThread类,使用方式如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
h = new HandlerThread("MyTestHandler3");
h.start();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
h.quit();
}
public void button3(View v){
TestHandler th = new TestHandler("button3", h.getLooper());
Log.d(TAG,th.getLooper().getThread().toString());
th.sendEmptyMessage(1);
}
mainActivity里面添加一个button3,点击事件处理就是HandlerThread的使用。首先HandlerThread被new出来后,要star()开启它,含有Handler处理机制的线程才算正真运行起来,看看HandlerThread类的run方法:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
和我们之前写的TestHandlerThread大同小异,一样的要Looper.prepare()和Looper.loop(),但它严谨些,添加了同步机制,同样也是提供了可以获取该线程的Looper对象的接口getLooper()。因此在oncreate()方法里new的HandlerThread对象并stat()开启,我们的MyTestHandler3线程就在等待消息处理了。button3方法里new出来的TestHandler实例时,传入MyTestHandler3线程的Looper对象与其进行绑定,之后使用该实例发送消息,就能直接发给MyTestHandler3线程中去处理了。点击按钮后打印信息如下:
09-18 14:43:59.279: D/MainActivity(21695): Thread[MyTestHandler3,5,main]
09-18 14:43:59.279: D/TestHanlder(21839): button3
运行整个工程后,使用eclipse的DDMS找到该工程的进程,一般为它的包名,接着打开它的线程列表,可以看到MyTestHandler和MyTestHandler3这两个线程已经被拉起并在等待消息处理,注意到它们的线程号和打印button2和button3时的线程号一样,说明了Handler处理已经真正切换到了该线程中处理了;
1 21695 Native 72 52 main
*2 21697 VmWait 144 7 GC
*3 21700 VmWait 0 0 Signal Catcher
*4 21701 Runnable 2267 6275 JDWP
*5 21702 VmWait 4 2 Compiler
*6 21703 Wait 0 0 ReferenceQueueDaemon
*7 21704 Wait 1 0 FinalizerDaemon
*8 21705 Wait 0 0 FinalizerWatchdogDaemon
9 21706 Native 0 1 Binder_1
10 21707 Native 0 0 Binder_2
11 21838 Native 0 0 MyTestHandler
12 21839 Native 0 0 MyTestHandler3
13 21841 Native 0 0 Binder_3
最后,在前面叙述中,留下了一个疑问,那就是主线程是什么时候拥有Looper对象的?当启动一个应用程序的时候,系统为应用程序创建进程时会传入一个java类(ActivityThread类),把该类的静态成员函数main作为程序运行入口点。而主线程是在应用程序进程开启后第一个被启动的线程,用来执行ActivityThread的main方法。在开始的时候提过,主线程比较特殊,它不像其他线程一样new出来了之后再start开启,它是由底层zygota fork出来并把AcitvityThread类main方法作为入口而跑起来的线程,ThreadActivity类也不是一个Thread,它只是一个final类,下面我们看看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());
Process.setArgV0("<pre-initialized>");
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");
}
}
这里我们看到了Looper.prepareMainLooper()和Looper.loop(),因为是主线程比较特殊,Looper还专门提供了一个prepareMainLooper方法专门用于主线程的prepare,不过该方法与非主线程的prepare方法大同小异。接下来看看Looper里面prepareMainLooper方法实现:
/** Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
... ... ...
/** 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");
}
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(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
这里可以 对比一下非主线程的prepare和主线程prepare的区别,主线程new出来的Looper对象传入的quitAllowed参数是false,代表着它的loop()是不允许被退出的。另外Looper类有一个成员变量mMainLooper,指向主线程的Looper对象,在prepareMainLooper()里被赋值,而且还对外提供了getMainLooper()方法,通过它可以在任何地方获得到主线程的Looper对象。Looper.prepareMainLooper()和Looper.loop()之后,主线程就可以接收并处理Handler消息了。我们知道Activity的生命周期中的onCreate、onResume和onPause等方法都是在主线程中执行的,然而这里的主线程一直在死循环里监听和处理Handler消息,它怎么去做这些事情的?很简单,往主线程里发相应的Handler消息,在主线程里触发Activity生命周期的相应操作。ActivityThread类为此提供了getHandler方法,该方法返回一个与主线程绑定的H实例,而H继承了Handler类,是ActivityThread类的内部类,代码实现如下:
... ...
final H mH = new H();
... ...
final Handler getHandler() {
return mH;
}
... ...
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 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);
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");
handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,
(msg.arg1&2) != 0);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break;
... ...
从这可以看到Activity生命周期的相关操作都是在H类的handlerMessage里,只要通过getHandler方法拿到H实例并发送相应消息就可以触发相应操作。那么会有谁来调用getHandler方法来发送这些消息呢?这里涉及到Android系统startActivity的流程及其binder通信,Handler机制只是它们实现中而使用到的一个部分。接下来截取下知乎上一位大神描述的一个例子:
从进程与线程间通信的角度,通过一张图加深大家对App运行过程的理解:
- 线程1的AMS中调用线程2的ATP;(由于同一个进程的线程间资源共享,可以相互直接调用,但需要注意多线程并发问题)
- 线程2通过binder传输到App进程的线程4;
- 线程4通过handler消息机制,将暂停Activity的消息发送给主线程;
- 主线程在looper.loop()中循环遍历消息,当收到暂停Activity的消息时,便将消息分发给ActivityThread.H.handleMessage()方法,再经过方法的调用,最后便会调用到Activity.onPause(),当onPause()处理完后,继续循环loop下去。
public class HandlerActivity extends Activity {
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler.sendMessageDelayed(Message.obtain(), 60000);
//just finish this activity
finish();
}
}
这里的mHandler是HandlerActivity类的内部匿名类,java的内部匿名类在构造时,编译器会隐性地加上一个引用类型的成员变量,该成员变量会指向HandlerActivity。接在HandlerActivity在oncreate的时候给了一个handler消息后finish掉自己了。此时内部匿名类一直持有着HandlerActivity的实例,因此该activity不会被GC回收。这里有一个疑问,它是内部类,外部类退出了内部类也一样会被销毁,但这里没有被销毁是因为,Message类引用了mHandler实例。在loop循环中被取到拿出来处理时,message对象引用着的mHandler,就是消息处理操作。只有消息处理操作完成,在loop方法最后调用Message的recyclerUnchecked方法,才把引用置空。上面例子发送了handler消息,它还没来得及处理,activity就退出,它持有的资源就不会得到释放,造成内存泄漏。可通过静态Handler内部类,handler外部类,handler里持有activity的弱引用 或 使用application的context。activity退出后,如果要处理的消息操作没有意义了,可在ondestroy里remove掉。部分例子如下:
public class HandlerActivity2 extends Activity {
private static final int MESSAGE_1 = 1;
private static final int MESSAGE_2 = 2;
private static final int MESSAGE_3 = 3;
private final Handler mHandler = new MyHandler(this);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler.sendMessageDelayed(Message.obtain(), 60000);
// just finish this activity
finish();
}
@Override
public void onDestroy() {
// If null, all callbacks and messages will be removed.
mHandler.removeCallbacksAndMessages(null);
}
public void todo() {
};
private static class MyHandler extends Handler {
private final WeakReference<HandlerActivity2> mActivity;
public MyHandler(HandlerActivity2 activity) {
mActivity = new WeakReference<HandlerActivity2>(activity);
}
@Override
public void handleMessage(Message msg) {
System.out.println(msg);
if (mActivity.get() == null) {
return;
}
mActivity.get().todo();
}
}
------------------------- 2018/7/4-------------------------- Handler扩展
1、Handler的消息队列是按照时间排序的(msg.when时间参数,以system boot为基准),时间最短的排的越靠近接口。
2、removeMessage只能移除消息队列里的消息,已经被next出去并进行处理的是无法取消的。
4、SyncBarrier消息就是一个target为null的message,一旦发送syncbarrier消息,那么这个消息后续的说有同步消息都不会被执行,只有异步消息才能通过被执行,提供了一个简单的优先级机制。MessageQueue的next方法如下:
// 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)
... ... ...
5、MessageQueue的IdleHandler接口用于在looper处理完所有消息并空闲时被调用,接口返回true表示下次空闲时可被再此调用,返回false就执行一次就完。
------------------------- 2023/7/22--------------------------
6、handler的removeCallbacksAndMessages(Object token)方法, 移除所有msg.obj == token的消息及callback, 需要注意这里是引用判断 ==,如果是token和msg.obj是两个字符串,即使内容相等但引用不等也不行了,但可用handler的 removeCallbacksAndEqualMessages(Object token),同样功能但用的equal方法进行判断,可惜这个是个@hide方法,应用访问不到。目前我使用的还是removeCallbacksAndMessages,对传入的token进行内容判断和转换,始终保证token引用的唯一性。