大概说说Handler机制

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构成的一个整体运行机制。我们可以从下图,大概了解它们的运行流程。


首先就是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运行过程的理解:

system_server进程是系统进程,java framework框架的核心载体,里面运行了大量的系统服务,比如这里提供ApplicationThreadProxy(简称ATP),ActivityManagerService(简称AMS),这个两个服务都运行在system_server进程的不同线程中,由于ATP和AMS都是基于IBinder接口,都是binder线程,binder线程的创建与销毁都是由binder驱动来决定的。 App进程则是我们常说的应用程序,主线程主要负责Activity/Service等组件的生命周期以及UI相关操作都运行在这个线程; 另外,每个App进程中至少会有两个binder线程 ApplicationThread(简称AT)和ActivityManagerProxy(简称AMP),除了图中画的线程,其中还有很多线程,比如signal catcher线程等,这里就不一一列举。Binder用于不同进程之间通信,由一个进程的Binder客户端向另一个进程的服务端发送事务,比如图中线程2向线程4发送事务;而handler用于同一个进程中不同线程的通信,比如图中线程4向主线程发送消息。 结合图说说Activity生命周期,比如暂停Activity,流程如下:
  1. 线程1的AMS中调用线程2的ATP;(由于同一个进程的线程间资源共享,可以相互直接调用,但需要注意多线程并发问题)
  2. 线程2通过binder传输到App进程的线程4;
  3. 线程4通过handler消息机制,将暂停Activity的消息发送给主线程;
  4. 主线程在looper.loop()中循环遍历消息,当收到暂停Activity的消息时,便将消息分发给ActivityThread.H.handleMessage()方法,再经过方法的调用,最后便会调用到Activity.onPause(),当onPause()处理完后,继续循环loop下去。
链接:http://www.zhihu.com/question/34652589/answer/90344494    来源:知乎binder客户端就是一个线程,在ActivityThread的main方法里, thread.attach(false)来创建,在上述提过使用ddms打开一个进程的线程列表,列表里有些binder_1、binder_2和binder_3就是这些线程。至此对Handler机制总结一下:Handler用于同一进程里线程间的通信,作用是将一个任务切换到某个指定的线程中去执行。然而Handler并不是专门用于更新UI,它只是常被开发者用来更新UI。例如我们可以内部运行一个拥有Handler机制功能的非UI线程(HandlerThread类使用),作为一个业务逻辑入口,消息处理里实现调用相关业务功能。UI上调用业务逻辑功能都要通过这个业务逻辑入口,即往这个非UI线程发送handler消息,这样利于代码组织结构清晰。
------------------------- 2016/11/29--------------------------在研究android内存泄漏时,发现有一种handler的使用方法会导致内存泄漏,这里简单记一下,具体如下例子:
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出去并进行处理的是无法取消的。
3、msg.what尽量不使用0,因为postDelayed(runnable, time)默认创建的msg的what就是0,一旦removeMessage,就会把所有msg.what等于0的消息移除,这样runnable也会被移除。
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引用的唯一性。


 





 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值