首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

Android Looper跟Handler

2013-01-26 
Android Looper和HandlerAndroid Looper和HandlerMessage:消息,其中包含了消息ID,消息处理对象以及处理的

Android Looper和Handler

Android Looper和Handler

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。

Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

?

Android系统的消息队列和消息循环都是针对具体线程的,一个线程可以存在(当然也可以不存在)一个消息队列和一个消 息循环(Looper),特定线程的消息只能分发给本线程,不能进行跨线程,跨进程通讯。但是创建的工作线程默认是没有消息循环和消息队列的,如果想让该 线程具有消息队列和消息循环,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。 如下例所示:

?

class LooperThread extends Thread {      public Handler mHandler;      public void run() {          Looper.prepare();          mHandler = new Handler() {              public void handleMessage(Message msg) {                  // process incoming messages here              }          };          Looper.loop();      }  }

这样你的线程就具有了消息处理机制了,在Handler中进行消息处理。


???? Activity是一个UI线程,运行于主线程中,Android系统在启动的时候会为Activity创建一个消息队列和消息循环(Looper)。详细实现请参考ActivityThread.java文件Android应用程序进程在启动的时候,会在进程中加载ActivityThread类,并且执行这个类的main函数,应用程序的消息循环过程就是在这个main函数里面实现的public final class ActivityThread {
......

public static final void main(String[] args) {
......

Looper.prepareMainLooper();

......

ActivityThread thread = new ActivityThread();
thread.attach(false);

......

Looper.loop();

......

thread.detach();

......
}
}这个函数做了两件事情,一是在主线程中创建了一个ActivityThread实例,二是通过Looper类使主线程进入消息循环中,这里我们只关注后者。

?? ? ? ?首先看Looper.prepareMainLooper函数的实现,这是一个静态成员函数,定义在frameworks/base/core/java/android/os/Looper.java文件中:

Android Looper跟Handler??1?//Looper类分析
??2?//没找到合适的分析代码的办法,只能这么来了。每个重要行的上面都会加上注释
??3?//功能方面的代码会在代码前加上一段分析
??4?public?class?Looper?{
??5????//static变量,判断是否打印调试信息。
??6?????private?static?final?boolean?DEBUG?=?false;
??7?????private?static?final?boolean?localLOGV?=?DEBUG???Config.LOGD?:?Config.LOGV;
??8?
??9?????//?sThreadLocal.get()?will?return?null?unless?you've?called?prepare().
?10?//线程本地存储功能的封装,TLS,thread?local?storage,什么意思呢?因为存储要么在栈上,例如函数内定义的内部变量。要么在堆上,例如new或者malloc出来的东西
?11?//但是现在的系统比如Linux和windows都提供了线程本地存储空间,也就是这个存储空间是和线程相关的,一个线程内有一个内部存储空间,这样的话我把线程相关的东西就存储到
?12?//这个线程的TLS中,就不用放在堆上而进行同步操作了。
?13?????private?static?final?ThreadLocal?sThreadLocal?=?new?ThreadLocal();
?14?//消息队列,MessageQueue,看名字就知道是个queue..
?15?????final?MessageQueue?mQueue;
?16?????volatile?boolean?mRun;
?17?//和本looper相关的那个线程,初始化为null
?18?????Thread?mThread;
?19?????private?Printer?mLogging?=?null;
?20?//static变量,代表一个UI?Process(也可能是service吧,这里默认就是UI)的主线程
?21?????private?static?Looper?mMainLooper?=?null;
?22?????
?23??????/**?Initialize?the?current?thread?as?a?looper.
?24???????*?This?gives?you?a?chance?to?create?handlers?that?then?reference
?25???????*?this?looper,?before?actually?starting?the?loop.?Be?sure?to?call
?26???????*?{@link?#loop()}?after?calling?this?method,?and?end?it?by?calling
?27???????*?{@link?#quit()}.
?28???????*/
?29?//往TLS中设上这个Looper对象的,如果这个线程已经设过了looper的话就会报错
?30?//这说明,一个线程只能设一个looper
?31?????public?static?final?void?prepare()?{
?32?????????if?(sThreadLocal.get()?!=?null)?{
?33?????????????throw?new?RuntimeException("Only?one?Looper?may?be?created?per?thread");
?34?????????}
?35?????????sThreadLocal.set(new?Looper());
?36?????}
?37?????
?38?????/**?Initialize?the?current?thread?as?a?looper,?marking?it?as?an?application's?main?
?39??????*??looper.?The?main?looper?for?your?application?is?created?by?the?Android?environment,
?40??????*??so?you?should?never?need?to?call?this?function?yourself.
?41??????*?{@link?#prepare()}
?42??????*/
?43??//由framework设置的UI程序的主消息循环,注意,这个主消息循环是不会主动退出的
?44?//????
?45?????public?static?final?void?prepareMainLooper()?{
?46?????????prepare();
?47?????????setMainLooper(myLooper());
?48?//判断主消息循环是否能退出....
?49?//通过quit函数向looper发出退出申请
?50?????????if?(Process.supportsProcesses())?{
?51?????????????myLooper().mQueue.mQuitAllowed?=?false;
?52?????????}
?53?????}
?54?
?55?????private?synchronized?static?void?setMainLooper(Looper?looper)?{
?56?????????mMainLooper?=?looper;
?57?????}
?58?????
?59?????/**?Returns?the?application's?main?looper,?which?lives?in?the?main?thread?of?the?application.
?60??????*/
?61?????public?synchronized?static?final?Looper?getMainLooper()?{
?62?????????return?mMainLooper;
?63?????}
?64?
?65?????/**
?66??????*??Run?the?message?queue?in?this?thread.?Be?sure?to?call
?67??????*?{@link?#quit()}?to?end?the?loop.
?68??????*/
?69?//消息循环,整个程序就在这里while了。
?70?//这个是static函数喔!
?71?????public?static?final?void?loop()?{
?72?????????Looper?me?=?myLooper();//从该线程中取出对应的looper对象
?73?????????MessageQueue?queue?=?me.mQueue;//取消息队列对象...
?74?????????while?(true)?{
?75?????????????Message?msg?=?queue.next();?//?might?block取消息队列中的一个待处理消息..
?76?????????????//if?(!me.mRun)?{//是否需要退出?mRun是个volatile变量,跨线程同步的,应该是有地方设置它。
?77?????????????//????break;
?78?????????????//}
?79?????????????if?(msg?!=?null)?{
?80?????????????????if?(msg.target?==?null)?{
?81?????????????????????//?No?target?is?a?magic?identifier?for?the?quit?message.
?82?????????????????????return;
?83?????????????????}
?84?????????????????if?(me.mLogging!=?null)?me.mLogging.println(
?85?????????????????????????">>>>>?Dispatching?to?"?+?msg.target?+?"?"
?86?????????????????????????+?msg.callback?+?":?"?+?msg.what
?87?????????????????????????);
?88?????????????????msg.target.dispatchMessage(msg);
?89?????????????????if?(me.mLogging!=?null)?me.mLogging.println(
?90?????????????????????????"<<<<<?Finished?to????"?+?msg.target?+?"?"
?91?????????????????????????+?msg.callback);
?92?????????????????msg.recycle();
?93?????????????}
?94?????????}
?95?????}
?96?
?97?????/**
?98??????*?Return?the?Looper?object?associated?with?the?current?thread.??Returns
?99??????*?null?if?the?calling?thread?is?not?associated?with?a?Looper.
100??????*/
101?//返回和线程相关的looper
102?????public?static?final?Looper?myLooper()?{
103?????????return?(Looper)sThreadLocal.get();
104?????}
105?
106?????/**
107??????*?Control?logging?of?messages?as?they?are?processed?by?this?Looper.??If
108??????*?enabled,?a?log?message?will?be?written?to?<var>printer</var>?
109??????*?at?the?beginning?and?ending?of?each?message?dispatch,?identifying?the
110??????*?target?Handler?and?message?contents.
111??????*?
112??????*?@param?printer?A?Printer?object?that?will?receive?log?messages,?or
113??????*?null?to?disable?message?logging.
114??????*/
115?//设置调试输出对象,looper循环的时候会打印相关信息,用来调试用最好了。
116?????public?void?setMessageLogging(Printer?printer)?{
117?????????mLogging?=?printer;
118?????}
119?????
120?????/**
121??????*?Return?the?{@link?MessageQueue}?object?associated?with?the?current
122??????*?thread.??This?must?be?called?from?a?thread?running?a?Looper,?or?a
123??????*?NullPointerException?will?be?thrown.
124??????*/
125?????public?static?final?MessageQueue?myQueue()?{
126?????????return?myLooper().mQueue;
127?????}
128?//创建一个新的looper对象,
129?//内部分配一个消息队列,设置mRun为true
130?????private?Looper()?{
131?????????mQueue?=?new?MessageQueue();
132?????????mRun?=?true;
133?????????mThread?=?Thread.currentThread();
134?????}
135?
136?????public?void?quit()?{
137?????????Message?msg?=?Message.obtain();
138?????????//?NOTE:?By?enqueueing?directly?into?the?message?queue,?the
139?????????//?message?is?left?with?a?null?target.??This?is?how?we?know?it?is
140?????????//?a?quit?message.
141?????????mQueue.enqueueMessage(msg,?0);
142?????}
143?
144?????/**
145??????*?Return?the?Thread?associated?with?this?Looper.
146??????*/
147?????public?Thread?getThread()?{
148?????????return?mThread;
149?????}
150?????//后面就简单了,打印,异常定义等。
151?????public?void?dump(Printer?pw,?String?prefix)?{
152?????????pw.println(prefix?+?this);
153?????????pw.println(prefix?+?"mRun="?+?mRun);
154?????????pw.println(prefix?+?"mThread="?+?mThread);
155?????????pw.println(prefix?+?"mQueue="?+?((mQueue?!=?null)???mQueue?:?"(null"));
156?????????if?(mQueue?!=?null)?{
157?????????????synchronized?(mQueue)?{
158?????????????????Message?msg?=?mQueue.mMessages;
159?????????????????int?n?=?0;
160?????????????????while?(msg?!=?null)?{
161?????????????????????pw.println(prefix?+?"??Message?"?+?n?+?":?"?+?msg);
162?????????????????????n++;
163?????????????????????msg?=?msg.next;
164?????????????????}
165?????????????????pw.println(prefix?+?"(Total?messages:?"?+?n?+?")");
166?????????????}
167?????????}
168?????}
169?
170?????public?String?toString()?{
171?????????return?"Looper{"
172?????????????+?Integer.toHexString(System.identityHashCode(this))
173?????????????+?"}";
174?????}
175?
176?????static?class?HandlerException?extends?Exception?{
177?
178?????????HandlerException(Message?message,?Throwable?cause)?{
179?????????????super(createMessage(cause),?cause);
180?????????}
181?
182?????????static?String?createMessage(Throwable?cause)?{
183?????????????String?causeMsg?=?cause.getMessage();
184?????????????if?(causeMsg?==?null)?{
185?????????????????causeMsg?=?cause.toString();
186?????????????}
187?????????????return?causeMsg;
188?????????}
189?????}
190?}Android Looper跟Handler?那怎么往这个消息队列中发送消息呢??调用looper的static函数myQueue可以获得消息队列,这样你就可用自己往里边插入消息了。不过这种方法比较麻烦,这个时候handler类就发挥作用了。先来看看handler的代码,就明白了。Android Looper跟Handler?1?class?Handler{
?2?..........
?3?//handler默认构造函数
?4?public?Handler()?{
?5?//这个if是干嘛用的暂时还不明白,涉及到java的深层次的内容了应该
?6?????????if?(FIND_POTENTIAL_LEAKS)?{
?7?????????????final?Class<??extends?Handler>?klass?=?getClass();
?8?????????????if?((klass.isAnonymousClass()?||?klass.isMemberClass()?||?klass.isLocalClass())?&&
?9?????????????????????(klass.getModifiers()?&?Modifier.STATIC)?==?0)?{
10?????????????????Log.w(TAG,?"The?following?Handler?class?should?be?static?or?leaks?might?occur:?"?+
11?????????????????????klass.getCanonicalName());
12?????????????}
13?????????}
14?//获取本线程的looper对象
15?//如果本线程还没有设置looper,这回抛异常
16?????????mLooper?=?Looper.myLooper();
17?????????if?(mLooper?==?null)?{
18?????????????throw?new?RuntimeException(
19?????????????????"Can't?create?handler?inside?thread?that?has?not?called?Looper.prepare()");
20?????????}
21?//无耻啊,直接把looper的queue和自己的queue搞成一个了
22?//这样的话,我通过handler的封装机制加消息的话,就相当于直接加到了looper的消息队列中去了
23?????????mQueue?=?mLooper.mQueue;
24?????????mCallback?=?null;
25?????}
26?//还有好几种构造函数,一个是带callback的,一个是带looper的
27?//由外部设置looper
28?????public?Handler(Looper?looper)?{
29?????????mLooper?=?looper;
30?????????mQueue?=?looper.mQueue;
31?????????mCallback?=?null;
32?????}
33?//?带callback的,一个handler可以设置一个callback。如果有callback的话,
34?//凡是发到通过这个handler发送的消息,都有callback处理,相当于一个总的集中处理
35?//待会看dispatchMessage的时候再分析
36?public?Handler(Looper?looper,?Callback?callback)?{
37?????????mLooper?=?looper;
38?????????mQueue?=?looper.mQueue;
39?????????mCallback?=?callback;
40?????}
41?//
42?//通过handler发送消息
43?//调用了内部的一个sendMessageDelayed
44?public?final?boolean?sendMessage(Message?msg)
45?????{
46?????????return?sendMessageDelayed(msg,?0);
47?????}
48?//FT,又封装了一层,这回是调用sendMessageAtTime了
49?//因为延时时间是基于当前调用时间的,所以需要获得绝对时间传递给sendMessageAtTime
50?public?final?boolean?sendMessageDelayed(Message?msg,?long?delayMillis)
51?????{
52?????????if?(delayMillis?<?0)?{
53?????????????delayMillis?=?0;
54?????????}
55?????????return?sendMessageAtTime(msg,?SystemClock.uptimeMillis()?+?delayMillis);
56?????}
57?
58?
59?public?boolean?sendMessageAtTime(Message?msg,?long?uptimeMillis)
60?????{
61?????????boolean?sent?=?false;
62?????????MessageQueue?queue?=?mQueue;
63?????????if?(queue?!=?null)?{
64?//把消息的target设置为自己,然后加入到消息队列中
65?//对于队列这种数据结构来说,操作比较简单了
66?????????????msg.target?=?this;
67?????????????sent?=?queue.enqueueMessage(msg,?uptimeMillis);
68?????????}
69?????????else?{
70?????????????RuntimeException?e?=?new?RuntimeException(
71?????????????????this?+?"?sendMessageAtTime()?called?with?no?mQueue");
72?????????????Log.w("Looper",?e.getMessage(),?e);
73?????????}
74?????????return?sent;
75?????}
76?//还记得looper中的那个消息循环处理吗
77?//从消息队列中得到一个消息后,会调用它的target的dispatchMesage函数
78?//message的target已经设置为handler了,所以
79?//最后会转到handler的msg处理上来
80?//这里有个处理流程的问题
81?public?void?dispatchMessage(Message?msg)?{
82?//如果msg本身设置了callback,则直接交给这个callback处理了
83?????????if?(msg.callback?!=?null)?{
84?????????????handleCallback(msg);
85?????????}?else?{
86?//如果该handler的callback有的话,则交给这个callback处理了---相当于集中处理
87???????????if?(mCallback?!=?null)?{
88?????????????????if?(mCallback.handleMessage(msg))?{
89?????????????????????return;
90?????????????????}
91????????????}
92?//否则交给派生处理,基类默认处理是什么都不干
93?????????????handleMessage(msg);
94?????????}
95?????}
96?..........
97?}Android Looper跟Handler

?

生成

???????Message msg = mHandler.obtainMessage();

???????msg.what = what;

???????msg.sendToTarget();

?

发送

???????MessageQueue queue = mQueue;

??????? if (queue != null) {

??????????? msg.target = this;

????????????sent = queue.enqueueMessage(msg, uptimeMillis);

????????}

在Handler.java的sendMessageAtTime(Message msg, long uptimeMillis)方法中,我们看到,它找到它所引用的MessageQueue,然后将Message的target设定成自己(目的是为了在处理消息环节,Message能找到正确的Handler),再将这个Message纳入到消息队列中。

抽取

??????? Looper me = myLooper();

??????? MessageQueue queue = me.mQueue;

??????? while (true) {

??????????? Message msg = queue.next(); // might block

??????????? if (msg != null) {

??????????????? if (msg.target == null) {

??????????????????? // No target is a magic identifier for the quit message.

??????????????????? return;

??????????????? }

??????????????? msg.target.dispatchMessage(msg);

??????????????? msg.recycle();

??????????? }

??????? }

在Looper.java的loop()函数里,我们看到,这里有一个死循环,不断地从MessageQueue中获取下一个(next方法)Message,然后通过Message中携带的target信息,交由正确的Handler处理(dispatchMessage方法)。

?

处理

??????? if (msg.callback != null) {

??????????? handleCallback(msg);

??????? } else {

??????????? if (mCallback != null) {

??????????????? if (mCallback.handleMessage(msg)) {

??????????????????? return;

??????????????? }

??????????? }

??????????? handleMessage(msg);

??????? }

在Handler.java的dispatchMessage(Message msg)方法里,其中的一个分支就是调用handleMessage方法来处理这条Message,而这也正是我们在职责处描述使用Handler时需要实现handleMessage(Message msg)的原因。

至于dispatchMessage方法中的另外一个分支,我将会在后面的内容中说明。

至此,我们看到,一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。

?

3)剩下的部分,我们将讨论一下Handler所处的线程及更新UI的方式。

在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象(系统已经帮我们创建了);在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。在这种情况下,通用的作法是:

??????????????? class LooperThread extends Thread {

?????????????????????????????? public Handler mHandler;

?????????????????????????????? public void run() {

?????????????????????????????????????????????? Looper.prepare();

?????????????????????????????????????????????? mHandler = new Handler() {

?????????????????????????????????????????????????????????????? public void handleMessage(Message msg) {

????????????????????????????????????????????????????????????????????????????? // process incoming messages here

?????????????????????????????????????????????????????????????? }

?????????????????????????????????????????????? };

?????????????????????????????????????????????? Looper.loop();

?????????????????????????????? }

??????????????? }

在创建Handler之前,为该线程准备好一个Looper(Looper.prepare),然后让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才能正常工作。

因此,Handler处理消息总是在创建Handler的线程里运行。而我们的消息处理中,不乏更新UI的操作,不正确的线程直接更新UI将引发异常。因此,需要时刻关心Handler在哪个线程里创建的。

?

如何更新UI才能不出异常呢?SDK告诉我们,有以下4种方式可以从其它线程访问UI线程:

·??????Activity.runOnUiThread(Runnable)

·??????View.post(Runnable)

·??????View.postDelayed(Runnable, long)

·??????Handler

其中,重点说一下的是View.post(Runnable)方法。在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此,我们可以毫无顾虑的来更新UI。

4)?几点小结

·??????Handler的处理过程运行在创建Handler的线程里

·??????一个Looper对应一个MessageQueue

·??????一个线程对应一个Looper

·??????一个Looper可以对应多个Handler

·??????不确定当前线程时,更新UI时尽量调用post方法

热点排行