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。
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 sThreadLocal = new ThreadLocal();
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 /**
* 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。
@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消息处理机制的线程了。
@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
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("");
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运行过程的理解:
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 mActivity;
public MyHandler(HandlerActivity2 activity) {
mActivity = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
System.out.println(msg);
if (mActivity.get() == null) {
return;
}
mActivity.get().todo();
}
}
------------------------- 2018/7/4-------------------------- Handler扩展
// 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就执行一次就完。