Android Loop&Handle学习总结 - New Start - 博客频道 - CSDN.NET
?????? 昨晚偷懒,这篇博客只写了一个标题,今天早晨一看,还有15的阅读量。实在是对不起那些同学.......换了是我,也会BS这样的LZ吧!sorry 啦
-------------------------------------------------------------------------------------------------------------------------------------------------------------
?????? 菜鸟我刚刚接触android源码的时候,当时连java语言都不太熟悉(菜鸟我一直是学C/C++),看到android某个应用的源码的时候,曾为这样的代码迷惑过。
?
[java] view plaincopyprint?
- private?class?MainHandler?extends?Handler?{??
- ????????@Override??
- ????????public?void?handleMessage(Message?msg)?{??
- ????????????switch?(msg.what)?{??
- ????????????????case?RESTART_PREVIEW:?{??
- ????????????????????restartPreview();??
- ????????????????????if?(mJpegPictureCallbackTime?!=?0)?{??
- ????????????????????????long?now?=?System.currentTimeMillis();??
- ????????????????????????mJpegCallbackFinishTime?=?now?-?mJpegPictureCallbackTime;??
- ????????????????????????Log.v(TAG,?"mJpegCallbackFinishTime?=?"??
- ????????????????????????????????+?mJpegCallbackFinishTime?+?"ms");??
- ????????????????????????mJpegPictureCallbackTime?=?0;??
- ????????????????????}??
- ????????????????????break;??
- ????????????????}??
- ??
- ????????????????...??
private class MainHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case RESTART_PREVIEW: { restartPreview(); if (mJpegPictureCallbackTime != 0) { long now = System.currentTimeMillis(); mJpegCallbackFinishTime = now - mJpegPictureCallbackTime; Log.v(TAG, "mJpegCallbackFinishTime = " + mJpegCallbackFinishTime + "ms"); mJpegPictureCallbackTime = 0; } break; } ? ? ? ? ? ? ? ...??????? 在同一个文件中不就是想调用restartPreview()函数吗?为什么不直接调用就好,还要发个消息然后在这个handleMessage()中来调用呢?初学菜鸟有没有同样的困惑?还是只有LZ一人太白痴了。
???? 那么到底为什么要这么做呢。是为了异步,是为了多线程,将一些耗时的操作放到一个子线程里面去,大家应该知道如果在android的应用程序主线程,也就是UI线程里面如果执行耗时操作超过5s就会报ANR(application not respon)错误。所以,为了避免ANR,android应用程序将一些耗时操作放到一个独立的工作线程中去。
????? 那么android是如何做到这点的呢?那个新的工作线程又是如何建立的?这就是android中Looper和Handler类的功劳。下面菜鸟来分析下首先看个类图:
? ? ??
?????? 从这个图看到Handler和HandlerThread类都有一个Looper成员变量。而且,Handler和Looper都有成员变量MessageQueue,下面我们看看Looper类和Handler类的作用。
Looper:
?????? Looper类,来实现消息循环,内部有一个消息队列。看到Looper类的构造函数是private的,这样外部没法实例化Looper对象,Looper对象的构造只能通过Looper的内部接口,来看一段函数:?
[java] view plaincopyprint?
- /**?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?final?void?prepare()?{??
- ????????if?(sThreadLocal.get()?!=?null)?{??
- ????????????throw?new?RuntimeException("Only?one?Looper?may?be?created?per?thread");??
- ????????}??
- ????????sThreadLocal.set(new?Looper());??
- ????}??
- ??????
- ????/**?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.?
- ?????*?{@link?#prepare()}?
- ?????*/??
- ???????
- ????public?static?final?void?prepareMainLooper()?{??
- ????????prepare();??
- ????????setMainLooper(myLooper());??
- ????????if?(Process.supportsProcesses())?{??
- ????????????myLooper().mQueue.mQuitAllowed?=?false;??
- ????????}??
- ????}??
/** 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 final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } /** 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. * {@link #prepare()} */ public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); if (Process.supportsProcesses()) { myLooper().mQueue.mQuitAllowed = false; } }??????? 其中函数prepareMainLooper()函数只在ActivityThread.java的main()函数中被调用过。这个prepareMainLooper()的作用保证每个调用线程都有一个Looper对象,这样应用程序的主线程就有一个Looper对象了,so应用程序主线程的消息循环建立了。
??????? 看看,perpare()函数中,有这样一句话?sThreadLocal.set(new Looper());其中sThreadLocal是一个ThreadLocal类型的变量。ThreadLocal表示这是一个线程的局部变量,google之看到下面这段解释。
??????? Implements a thread-local storage, that is, a variable for which each thread has its own value. All threads share the same
ThreadLocal
object, but each sees a different value when accessing it, and changes
made by one thread do not affect the other threads. The implementation supportsnull
values.?????? 菜鸟斗胆来翻译下,ThreadLocal实现了一种线程的局部存储,ThreadLocal代表一种线程局部变量,对于这种变量来说ThreadLocal保证每个线程都有一个独立的值(value),所有线程都共有一个ThreadLocal对象,但是每个线程在访问这些变量的时候能得到不同的值,每个线程可以更改这些变量并且不会影响其他的线程。ThreadLocal支持NULL值。/*那位大牛有更好的翻译,分享下呗*/
?????? 其中ThreadLocal开放了两个接口:
???????????public Tget():获取调用线程的局部变量
?????? public void set(T value) :设置调用线程的局部变量
?????? perpare()函数的这种处理方式保证在每个调用该函数的线程都有一个独立的Looper对象。
??????
Handler:????
?????? Handler的作用是处理消息,他封装了消息的投递和对消息的处理。通过上面的图可以看到Handler类有一个Looper和MessageQueue成员变量,Handler类有4个不同的构造函数如下:
[java] view plaincopyprint?
- public?Handler()?{??
- ????????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());??
- ????????????}??
- ????????}??
- ????????<span?style="color:#000000;">/*Handler默认的构造函数,使用当前线程(调用线程)的Looper对象给Handler成员变量mLooper赋值*/</span>???
- ????????mLooper?=?Looper.myLooper();??
- ????????if?(mLooper?==?null)?{??
- ????????????throw?new?RuntimeException(??
- ????????????????"Can‘t?create?handler?inside?thread?that?has?not?called?Looper.prepare()");??
- ????????}??
- ????????<span?style="color:#000000;">/*使用当前线程(调用线程)的消息队列给Handler的mQueue赋值*/</span>??
- ????????mQueue?=?mLooper.mQueue;??
- ????????mCallback?=?null;??
- ????}??
- ??
- ????/**?
- ?????*?Constructor?associates?this?handler?with?the?queue?for?the?
- ?????*?current?thread?and?takes?a?callback?interface?in?which?you?can?handle?
- ?????*?messages.?
- ?????*/??
- ????public?Handler(Callback?callback)?{??
- ????????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;??
- ????????<span?style="color:#000000;">/*跟默认构造函数差不多,只不过带了一个callback*/</span>??
- ????????mCallback?=?callback;??
- ????}??
- ??
- ????/**?
- ?????*?Use?the?provided?queue?instead?of?the?default?one.?
- ?????*/??
- ????public?Handler(Looper?looper)?{??
- ????????<span?style="color:#000000;">/*使用指定的Looper来给Handler类的mLooper赋值*/</span>??
- ????????mLooper?=?looper;??
- ????????mQueue?=?looper.mQueue;??
- ????????mCallback?=?null;??
- ????}??
- ??
- ????/**?
- ?????*?Use?the?provided?queue?instead?of?the?default?one?and?take?a?callback?
- ?????*?interface?in?which?to?handle?messages.?
- ?????*/??
- ????public?Handler(Looper?looper,?Callback?callback)?{??
- ????????<span?style="color:#000000;">/*使用指定的Looper和CallBack来初始化Handler*/</span>??
- ????????mLooper?=?looper;??
- ????????mQueue?=?looper.mQueue;??
- ????????mCallback?=?callback;??
- ????}??
public Handler() { 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()); } } ? ? ? ? /*Handler默认的构造函数,使用当前线程(调用线程)的Looper对象给Handler成员变量mLooper赋值*/ mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can‘t create handler inside thread that has not called Looper.prepare()"); } ? ? ? ? /*使用当前线程(调用线程)的消息队列给Handler的mQueue赋值*/ mQueue = mLooper.mQueue; mCallback = null; } /** * Constructor associates this handler with the queue for the * current thread and takes a callback interface in which you can handle * messages. */ public Handler(Callback callback) { 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; ? ? ? ? /*跟默认构造函数差不多,只不过带了一个callback*/ mCallback = callback; } /** * Use the provided queue instead of the default one. */ public Handler(Looper looper) { ? ? ? ? /*使用指定的Looper来给Handler类的mLooper赋值*/ mLooper = looper; mQueue = looper.mQueue; mCallback = null; } /** * Use the provided queue instead of the default one and take a callback * interface in which to handle messages. */ public Handler(Looper looper, Callback callback) { ? ? ? ? /*使用指定的Looper和CallBack来初始化Handler*/ mLooper = looper; mQueue = looper.mQueue; mCallback = callback; }?????
?????? 可以看到Handler类的成员变量MessageQueue mQueue都会指向Looper类的的MessageQueue,Handler为什么要这么做呢?
????? 下面看看Handler类提供那些接口:
sendEmptyMessage
[java] view plaincopyprint?
- public?final?Message?obtainMessage(int?what)??
- ????{??
- ????????return?Message.obtain(this,?what);??
- ????}??
- ??
- /**?
- ?????*?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);??
- ????????}??
- ????}??
- ??
- /**?
- ?????*?Sends?a?Message?containing?only?the?what?value.?
- ?????*???
- ?????*[email protected]?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?sendEmptyMessage(int?what)??
- ????{??
- ????????return?sendEmptyMessageDelayed(what,?0);??
- ????}??
- ??
- /**?
- ?????*?Remove?any?pending?posts?of?messages?with?code?‘what‘?that?are?in?the?
- ?????*?message?queue.?
- ?????*/??
- ????public?final?void?removeMessages(int?what)?{??
- ????????mQueue.removeMessages(this,?what,?null,?true);??
- ????}??
- ??
- ?????/**?
- ?????*<span?style="color:#ff0000;">注意这个函数,函数将有子类实现</span>?
- ?????*?Subclasses?must?implement?this?to?receive?messages.?
- ?????*/??
- ????public?void?handleMessage(Message?msg)?{??
- ????}??
public final Message obtainMessage(int what) { return Message.obtain(this, what); } /** * 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); } } /** * Sends a Message containing only the what value. * * @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 sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } /** * Remove any pending posts of messages with code ‘what‘ that are in the * message queue. */ public final void removeMessages(int what) { mQueue.removeMessages(this, what, null, true); } ? ? ?/** ? ? ?*注意这个函数,函数将有子类实现 * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }??????? 其中sendMessage函数都会调用到sendMessageAtTime函数,下面看下sendMessageAtTime(Message msg, long uptimeMillis)函数的实现
?
[java] view plaincopyprint?
- public?boolean?sendMessageAtTime(Message?msg,?long?uptimeMillis)??
- ????{??
- ????????boolean?sent?=?false;??
- ????????MessageQueue?queue?=?mQueue;??
- ????????if?(queue?!=?null)?{??
- ????????????<span?style="color:#ff0000;">/*看到Message的target变量指向当前这个Handler类*/</span>??
- ????????????msg.target?=?this;??
- ????????????sent?=?queue.enqueueMessage(msg,?uptimeMillis);??
- ????????}??
- ????????else?{??
- ????????????RuntimeException?e?=?new?RuntimeException(??
- ????????????????this?+?"?sendMessageAtTime()?called?with?no?mQueue");??
- ????????????Log.w("Looper",?e.getMessage(),?e);??
- ????????}??
- ????????return?sent;??
- ????}??
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { ? ? ? ? ? ? /*看到Message的target变量指向当前这个Handler类*/ msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; }?????? msg.target指明了这个msg将有谁来处理,在这里msg.target=this,Handler类除了封装消息添加外还封装了消息处理的接口。
Looper和Handler的联系:
?????????? 本菜鸟不才不知道上面的分析有没有错误,有没有让很多初学者犯迷糊,下面我将分析以下Looper和Handler类的联系,希望可以把上面的知识点串联起来。
?????????? 当调用Looper类的loop()函数的时候当前线程就进入到一个消息循环中去。看看这个loop()@Looper.java函数先.
[java] view plaincopyprint?
- <span?style="font-size:18px;">/**?
- ?????*??Run?the?message?queue?in?this?thread.?Be?sure?to?call?
- ?????*?{@link?#quit()}?to?end?the?loop.?
- ?????*/??
- ????public?static?final?void?loop()?{??
- ????????Looper?me?=?myLooper();??
- ????????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();??
- ??????????
- ????????while?(true)?{??
- ????????????Message?msg?=?queue.next();?//?might?block??
- ????????????//if?(!me.mRun)?{??
- ????????????//????break;??
- ????????????//}??
- ????????????if?(msg?!=?null)?{??
- ????????????????if?(msg.target?==?null)?{??
- ????????????????????//?No?target?is?a?magic?identifier?for?the?quit?message.??
- ????????????????????return;??
- ????????????????}??
- ????????????????if?(me.mLogging!=?null)?me.mLogging.println(??
- ????????????????????????">>>>>?Dispatching?to?"?+?msg.target?+?"?"??
- ????????????????????????+?msg.callback?+?":?"?+?msg.what??
- ????????????????????????);??
- ????????????????<span?style="color:#ff0000;">/*下面的函数将Looper类和Handler类联系起来*/</span>??
- ????????????????msg.target.dispatchMessage(msg);??
- ????????????????if?(me.mLogging!=?null)?me.mLogging.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("Looper",?"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.recycle();??
- ????????????}??
- ????????}??
- ????}</span>??
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static final void loop() { Looper me = myLooper(); 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(); while (true) { Message msg = queue.next(); // might block //if (!me.mRun) { // break; //} if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what ); ? ? ? ? ? ? ? ? /*下面的函数将Looper类和Handler类联系起来*/ msg.target.dispatchMessage(msg); if (me.mLogging!= null) me.mLogging.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("Looper", "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.recycle(); } } }??????? 可以看到当前线程不断的从消息队列中取出消息,如果消息的target成员变量为null,就表示要退出消息循环了,否则的话就要调用这个target对象的dispatchMessage成员函数来处理这个消息,这个target对象的类型为Handler。
???????????
???????????????? 其实这个Looper和Handler类中消息传递的机制还是很复杂到,用到了Linux中Pipe的相关知识,我太菜还不能做出更深的分析,以后有时间会好好学习下,在完善下这部份的知识。
????????? 好了,这篇blog就说到这里吧。下篇blog我会试着分析下,Handler和Looper的同步问题。届时会顺便学习一下HandlerThread类。
?
????????????? 忘了说,如果哪位大牛发现我这篇blog有什么错误,敬请指正,免得误导了跟我一样的菜鸟
Android异步处理三:Handler+Looper+MessageQueue深入详解 - lzc的专栏 - 博客频道 - CSDN.NET
在《Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面》中,我们讲到使用Thread+Handler的方式来实现界面的更新,其实是在非UI线程发送消息到UI线程,通知UI线程进行界面更新,这一篇我们将深入学习Android线程间通讯的实现原理。
概述:Android使用消息机制实现线程间的通信,线程通过Looper建立自己的消息循环,MessageQueue是FIFO的消息队列,Looper负责从MessageQueue中取出消息,并且分发到消息指定目标Handler对象。Handler对象绑定到线程的局部变量Looper,封装了发送消息和处理消息的接口。
例子:在介绍原理之前,我们先介绍Android线程通讯的一个例子,这个例子实现点击按钮之后从主线程发送消息"hello"到另外一个名为” CustomThread”的线程。
LooperThreadActivity.java
?
[java] view plaincopyprint?
- package?com.zhuozhuo;??
- ??
- import?android.app.Activity;??
- import?android.os.Bundle;??
- import?android.os.Handler;??
- import?android.os.Looper;??
- import?android.os.Message;??
- import?android.util.Log;??
- import?android.view.View;??
- import?android.view.View.OnClickListener;??
- ??
- public?class?LooperThreadActivity?extends?Activity{??
- ????/**?Called?when?the?activity?is?first?created.?*/??
- ??????
- ????private?final?int?MSG_HELLO?=?0;??
- ????private?Handler?mHandler;??
- ??????
- ????@Override??
- ????public?void?onCreate(Bundle?savedInstanceState)?{??
- ????????super.onCreate(savedInstanceState);??
- ????????setContentView(R.layout.main);??
- ????????new?CustomThread().start();//新建并启动CustomThread实例??
- ??????????
- ????????findViewById(R.id.send_btn).setOnClickListener(new?OnClickListener()?{??
- ??????????????
- ????????????@Override??
- ????????????public?void?onClick(View?v)?{//点击界面时发送消息??
- ????????????????String?str?=?"hello";??
- ????????????????Log.d("Test",?"MainThread?is?ready?to?send?msg:"?+?str);??
- ????????????????mHandler.obtainMessage(MSG_HELLO,?str).sendToTarget();//发送消息到CustomThread实例??
- ??????????????????
- ????????????}??
- ????????});??
- ??????????
- ????}??
- ??????
- ??????
- ??????
- ??????
- ??????
- ????class?CustomThread?extends?Thread?{??
- ????????@Override??
- ????????public?void?run()?{??
- ????????????//建立消息循环的步骤??
- ????????????Looper.prepare();//1、初始化Looper??
- ????????????mHandler?=?new?Handler(){//2、绑定handler到CustomThread实例的Looper对象??
- ????????????????public?void?handleMessage?(Message?msg)?{//3、定义处理消息的方法??
- ????????????????????switch(msg.what)?{??
- ????????????????????case?MSG_HELLO:??
- ????????????????????????Log.d("Test",?"CustomThread?receive?msg:"?+?(String)?msg.obj);??
- ????????????????????}??
- ????????????????}??
- ????????????};??
- ????????????Looper.loop();//4、启动消息循环??
- ????????}??
- ????}??
- }??
package com.zhuozhuo; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; public class LooperThreadActivity extends Activity{ /** Called when the activity is first created. */ private final int MSG_HELLO = 0; private Handler mHandler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); new CustomThread().start();//新建并启动CustomThread实例 findViewById(R.id.send_btn).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) {//点击界面时发送消息 String str = "hello"; Log.d("Test", "MainThread is ready to send msg:" + str); mHandler.obtainMessage(MSG_HELLO, str).sendToTarget();//发送消息到CustomThread实例 } }); } class CustomThread extends Thread { @Override public void run() { //建立消息循环的步骤 Looper.prepare();//1、初始化Looper mHandler = new Handler(){//2、绑定handler到CustomThread实例的Looper对象 public void handleMessage (Message msg) {//3、定义处理消息的方法 switch(msg.what) { case MSG_HELLO: Log.d("Test", "CustomThread receive msg:" + (String) msg.obj); } } }; Looper.loop();//4、启动消息循环 } } }main.xml
?
?
[html] view plaincopyprint?
- <?xml?version="1.0"?encoding="utf-8"?>??
- <LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"??
- ????android:orientation="vertical"??
- ????android:layout_width="fill_parent"??
- ????android:layout_height="fill_parent"??
- ????>??
- <TextView????
- ????android:layout_width="fill_parent"???
- ????android:layout_height="wrap_content"???
- ????android:text="@string/hello"??
- ????/>??
- <Button?android:text="发送消息"?android:id="@+id/send_btn"?android:layout_width="wrap_content"?android:layout_height="wrap_content"></Button>??
- </LinearLayout>??
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:text="发送消息" android:id="@+id/send_btn" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> </LinearLayout>?
Log打印结果:
?
原理:
?
我们看到,为一个线程建立消息循环有四个步骤:
1、? 初始化Looper
2、? 绑定handler到CustomThread实例的Looper对象
3、? 定义处理消息的方法
4、? 启动消息循环
下面我们以这个例子为线索,深入Android源代码,说明Android Framework是如何建立消息循环,并对消息进行分发的。
1、? 初始化Looper : Looper.prepare()
Looper.java
[java] view plaincopyprint?
- private?static?final?ThreadLocal?sThreadLocal?=?new?ThreadLocal();??
- public?static?final?void?prepare()?{??
- ????????if?(sThreadLocal.get()?!=?null)?{??
- ????????????throw?new?RuntimeException("Only?one?Looper?may?be?created?per?thread");??
- ????????}??
- ????????sThreadLocal.set(new?Looper());??
- }??
private static final ThreadLocal sThreadLocal = new ThreadLocal(); public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); }一个线程在调用Looper的静态方法prepare()时,这个线程会新建一个Looper对象,并放入到线程的局部变量中,而这个变量是不和其他线程共享的(关于ThreadLocal的介绍)。下面我们看看Looper()这个构造函数:
Looper.java
[java] view plaincopyprint?
- final?MessageQueue?mQueue;??
- private?Looper()?{??
- ????????mQueue?=?new?MessageQueue();??
- ????????mRun?=?true;??
- ????????mThread?=?Thread.currentThread();??
- ????}??
final MessageQueue mQueue; private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); }可以看到在Looper的构造函数中,创建了一个消息队列对象mQueue,此时,调用Looper. prepare()的线程就建立起一个消息循环的对象(此时还没开始进行消息循环)。
2、? 绑定handler到CustomThread实例的Looper对象 : mHandler= new Handler()
Handler.java
[java] view plaincopyprint?
- final?MessageQueue?mQueue;??
- ?final?Looper?mLooper;??
- public?Handler()?{??
- ????????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?=?null;??
- }??
final MessageQueue mQueue; final Looper mLooper; public Handler() { 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 = null; }Handler通过mLooper = Looper.myLooper();绑定到线程的局部变量Looper上去,同时Handler通过mQueue =mLooper.mQueue;获得线程的消息队列。此时,Handler就绑定到创建此Handler对象的线程的消息队列上了。
3、定义处理消息的方法:Override public void handleMessage (Message msg){}
? ? ?子类需要覆盖这个方法,实现接受到消息后的处理方法。
4、启动消息循环 : Looper.loop()
? ? ? 所有准备工作都准备好了,是时候启动消息循环了!Looper的静态方法loop()实现了消息循环。
Looper.java
[java] view plaincopyprint?
- public?static?final?void?loop()?{??
- ???????Looper?me?=?myLooper();??
- ???????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();??
- ?????????
- ???????while?(true)?{??
- ???????????Message?msg?=?queue.next();?//?might?block??
- ???????????//if?(!me.mRun)?{??
- ???????????//????break;??
- ???????????//}??
- ???????????if?(msg?!=?null)?{??
- ???????????????if?(msg.target?==?null)?{??
- ???????????????????//?No?target?is?a?magic?identifier?for?the?quit?message.??
- ???????????????????return;??
- ???????????????}??
- ???????????????if?(me.mLogging!=?null)?me.mLogging.println(??
- ???????????????????????">>>>>?Dispatching?to?"?+?msg.target?+?"?"??
- ???????????????????????+?msg.callback?+?":?"?+?msg.what??
- ???????????????????????);??
- ???????????????msg.target.dispatchMessage(msg);??
- ???????????????if?(me.mLogging!=?null)?me.mLogging.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("Looper",?"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.recycle();??
- ???????????}??
- ???????}??
- ???}??
public static final void loop() { Looper me = myLooper(); 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(); while (true) { Message msg = queue.next(); // might block //if (!me.mRun) { // break; //} if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what ); msg.target.dispatchMessage(msg); if (me.mLogging!= null) me.mLogging.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("Looper", "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.recycle(); } } }while(true)体现了消息循环中的“循环“,Looper会在循环体中调用queue.next()获取消息队列中需要处理的下一条消息。当msg != null且msg.target != null时,调用msg.target.dispatchMessage(msg);分发消息,当分发完成后,调用msg.recycle();回收消息。
msg.target是一个handler对象,表示需要处理这个消息的handler对象。Handler的void dispatchMessage(Message msg)方法如下:
Handler.java
[java] view plaincopyprint?
- public?void?dispatchMessage(Message?msg)?{??
- ????????if?(msg.callback?!=?null)?{??
- ????????????handleCallback(msg);??
- ????????}?else?{??
- ????????????if?(mCallback?!=?null)?{??
- ????????????????if?(mCallback.handleMessage(msg))?{??
- ????????????????????return;??
- ????????????????}??
- ????????????}??
- ????????????handleMessage(msg);??
- ????????}??
- }??
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }可见,当msg.callback== null 并且mCallback == null时,这个例子是由handleMessage(msg);处理消息,上面我们说到子类覆盖这个方法可以实现消息的具体处理过程。
?
总结:从上面的分析过程可知,消息循环的核心是Looper,Looper持有消息队列MessageQueue对象,一个线程可以把Looper设为该线程的局部变量,这就相当于这个线程建立了一个对应的消息队列。Handler的作用就是封装发送消息和处理消息的过程,让其他线程只需要操作Handler就可以发消息给创建Handler的线程。由此可以知道,在上一篇《Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面》中,UI线程在创建的时候就建立了消息循环(在ActivityThread的public static final void main(String[] args)方法中实现),因此我们可以在其他线程给UI线程的handler发送消息,达到更新UI的目的。