学习android到今天也将近3个月了,虽然各种界面各种组件一直在欢快的用着,但有一天忽然发现,一些简单的东西去不是很理解:比如Bundle和Handler。于是就抽空好好阅读了下adk文档。现在也算是理解一二了,技术需要分享,于是乎花了半天的时间整理了这篇文章。

1、Bundle(打酱油的)

这应该是任何一个学习android的人创建的第一个hello world程序都会遇到的一个类,它是activity的oncreate的入参,但由于做东西的时候很少会遇到它,也就一直没在意。

这个类很简单,先听听官方的解释:“A mapping from String values to various Parcelable types.”

Soga,原来就是一个String - Object的映射表,同时又是支持序列化的。

再看代码:“final class Bundle implements Parcelable, Cloneable ”。实现了两个接口,前者是序列化接口,后置是浅拷贝和深拷贝的接口,具体实现就不再说了,这个不是重点。

总之一句话,Bundle就是为了实现数据传输而生的,比如activity之间。通常Bundle会附在intent里面intent.putExtra()。

好了,打住,进入下一个议题:消息循环!

2、Windows消息循环

做过客户端的肯定都会接触到一个概念:UI线程。说白了,UI线程和普通工作线程的区别就在于消息循环。消息循环就是用来处理分发相关线程消息队列中的消息,Android和Windows都是如此。作为一名曾经的windows开发人员,研究的第一个点也是系统对UI的消息处理流程,不然干活都没底气。

int_WinMain(args...){//WNDdefinition......while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessage(&msg);}}LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam){switch(message){......}}


上面就是经过简化后的一个最基本的windows的创建窗口的过程。其中main函数里面的while就是一个消息循环,来不断从消息队列里面读取消息并dispatch消息。dispatch的消息均会进入到消息处理回调函数WndProc中完成消息的处理。这个程序的main线程也就是通常说的UI线程。假如我们另起一个线程包含了上面的while循环,则那个线程也照样可以创建窗口什么的,那么它也是一个UI线程。

如果对win32的ui感兴趣,可以参考http://blog.csdn.net/cheneywong/article/details/8847810

上面说了这么些的windows相关技术,其实就是想描述下窗口处理的基本原理,因为有些概念在windows上更易懂写,这样再看android的时候容易理解些。


3、Android的Looper

官方解释:Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, callprepare()in the thread that is to run the loop, and thenloop()to have it process messages until the loop is stopped.

很明白,looper就是一个用来处理消息的消息循环。默认的Thread也是不具有处理消息的能力,需要添加Looper来实现。说白了,android中的UI线程也就是带有一个Looper的Thread,用户所有的操作产生的消息均通过Looper来分发处理(这句没有看代码验证,但应该也是八九不离十了)。

和上一节比较我们发现好像少了一点东西 -- 消息处理回调函数WndProc。

Most interaction with a message loop is through theHandlerclass.”

这句话也引出了Looper和Hanlder的关系了。一个消息循环分发消息,一个消息处理。如下一段实例代码,演示了线程中添加消息循环并处理的过程:

classLooperThreadextendsThread{publicHandlermHandler;publicvoidrun(){Looper.prepare();mHandler=newHandler(){publicvoidhandleMessage(Messagemsg){//processincomingmessageshere}};Looper.loop();}}


看了这段代码,我就立刻产生了一个疑问,windows中的wndproc是需要注册才能进入处理的,那上段代码handler没有注册却能接收并处理消息!!

4、Android的Handler

官方解释:A Handler allows you to send and processMessageand Runnable objects associated with a thread'sMessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it-- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
简单翻译:Handler允许你向线程的MessageQueue发送消息,同时还能够处理该消息队列里的Message和Runnable。每个handler只能关联一个线程,并在创建的时候和线程绑定。


原来创建Hanlder的时候,它会自己绑定到线程和消息队列上,这就解释了上一节的疑问了。


另外值得注意的一条规则:每个Handler只会和一个Thread绑定,即创建它的Thread。后面会讲到这条规则的用处。

这里面又引入了两个概念:Message和向消息队列发送消息。

Message

消息体,查看源码大致包含了如下几个核心成员:

Bundle date ; // 消息体包含的数据

Handler target; // 消息对应的“target", 即由谁来处理

Runable callback; // 消息处理的回调

Message next; // 下一条消息

5、再看Looper

Looper的结构相对简单,主要有以下两个成员

{

final MessageQueue mQueue;

final Thread mThread;

}

通过成员变量,我们可以看出一个消息循环Looper均和一个Thread相关联,同时还会附带一个消息队列MessageQueue。

另外,还有两个静态成员:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

该对象可以理解成管理Thread和Looper的关系就好了。

private static Looper sMainLooper;

主线程的Looper。这样,任何就可以在任何线程获取到主线程(UI线程)的消息循环体了,进而可以向UI线程发送消息。

最后,我们再看下之前代码中出现的Looper.prepare()和Looper.loop()。这两个函数均是静态函数


prepare()

通过ThreadLocal创建Looper。


loop():

简化后的伪代码大致如下:

publicstaticvoidloop(){loop=getThisThreadLooper();queue=loop.mQueue;for(;;){msg=queue.next();//分发消息msg.target.dispatchMessage(msg);msg.recycle();}}

原来loop函数也就是一个无线循环,不断的从消息队列里面取出消息并交给Message中的目标Handler处理。好了,这就清晰了,消息循环原来如此简单。


附加:prepareMainLooper

publicstaticvoidprepareMainLooper(){prepare(false);synchronized(Looper.class){if(sMainLooper!=null){thrownewIllegalStateException("ThemainLooperhasalreadybeenprepared.");}sMainLooper=myLooper();}}

该函数顾名思义,就是来准备主线程(UI线程)的消息循环,代码的注释中也说明了:该函数是初始化application的主looper。该函数有android系统来调用,我们不应该自己来调用,不然会抛出异常。


6、再看Handler

上一节中出现了一个函数Handler.dispatchMessage(Message). 下面我们也会重点分析该函数的。

{finalMessageQueuemQueue;finalLoopermLooper;finalCallbackmCallback;}

Handler中的成员主要有上面3个,消息队列、消息循环和回调Callback。


(1)初始化

获取创建自己的线程的消息循环以及消息队列:mLooper = Looper.myLooper();

另外用户可以为Handler指定一个Callback。

(2)Callback接口和handleMessage成员方法

Handler内部定义了如下接口:

publicinterfaceCallback{publicbooleanhandleMessage(Messagemsg);//返回值意思就是callback处理完之后是否还需要继续处理,true就是已经处理过了,不需要再进一步处理}

另外值得注意的是Handler自己还有一个成员函数

publicvoidhandleMessage(Messagemsg){}

擦,你这是要闹哪样!!

查看下代码的注释:

Callback:”Callback interface you can use when instantiating a Handler to avoidhaving to implement your own subclass of Handler.“

handleMessage成员函数:”Subclasses must implement this to receive messages.“

这样就水落石出了:成员函数主要用在用户自己继承Handler实现时来处理message的,而Callback接口则是为了用户直接创建Handler时能够处理message用的,而不必通过子类实现。


(3)dispatchMessage

Message中有一个Runnable的Callback成员,现在Handler中也有一个Callback,另外Handler还有一个成员函数handleMessage(Message),哇塞,晕掉了有木有,这三个必须要有一个执行次序。代码如下:

publicvoiddispatchMessage(Messagemsg){if(msg.callback!=null){msg.callback.run();}else{if(mCallback!=null){if(mCallback.handleMessage(msg)){return;}}handleMessage(msg);}}

即优先级为:1. 消息体中的Runnable; 2. 如果为空则执行创建handler时指定的Callback;3. 如果没指定或者返回值为false的话就执行handler的handleMessage方法。

至此,android中线程的消息循环和消息队列就说明的差不多了。

Handler的Send/Post Mesage

在SDK文档中的描述Handler,其有两大主要用处:其一,安排message和runnable在某一时间点执行;其二,向其他线程的消息队列中发送消息(比如UI主线程)。

其中第二项功能就是我们通常用来在异步线程和UI线程打交道的方法了。这主要通过Handler提供的send和post系列方法完成。send对应message,post对应Runnable。

如下:

post(Runnable)

postAtTime(Runnable, long)

postDelayed(Runnable, long)

sendEmptyMessage(int)

sendMessage(Message)

sendMessageAtTime(Message, long)

sendMessageDelayed(Message, long)

每个方法的具体含义请自行查看SDK文档。这里还是要解释下post的实现:

publicfinalbooleanpost(Runnabler){returnsendMessageDelayed(getPostMessage(r),0);}publicfinalbooleansendMessage(Messagemsg){returnsendMessageDelayed(msg,0);}publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){MessageQueuequeue=mQueue;if(queue==null){//exceptionreturnfalse;}returnenqueueMessage(queue,msg,uptimeMillis);}


原来post也是将Runnable转换成一个message(还记得Message有一个Runnable成员吗),然后调用send的delay方法。最终的sendMessage也只是将消息压入消息队列中。

注意:这里面的post和send含义和Windows应用程序的post和send的含义是不同的。

(1)线程内

上面的分析,我们就可以在线程内向handler发送自定义message或post一个runnable。

(2)线程间

之前我们说过:一个Handler只能和创建它的线程绑定在一起,这样我们就可以在主线程创建一个Handler,然后再工作线程中向这个Handler 进行send 或post操作,这样创建的message均会加入到UI线程的消息队列中并被执行,这也就实现了UI线程和普通工作线程的通信。如下一个代码示例:

classMyActivity{Handlerhandler;......voidinit(){handler=newHandler(){@OverridepublicvoidhandleMessage(Messagemsg){//处理消息:将网络获取的数据在UI上表现出来......}};}voidgetDataFormNet(){Threadthread=newThread(newRunnable(){@Overridepublicvoidrun(){//网络操作......handler.sendMessage(newMessage());}});thread.start();}}


OVER了,学习时间不长,如有错误请指正~~






更多相关文章

  1. Android实现与SQL连接
  2. Android(安卓)View使用详解
  3. Android仿人人客户端(v5.7.1)——网络模块优化
  4. android初学者_面向初学者的Android(安卓)Studio,第4部分:调试工具
  5. Android中的Handler使用总结
  6. 阿里Android开发手册正式版一览
  7. Android消息机制字典型探究(一)
  8. Android(安卓)异步调用,AsyncTask的简单用法
  9. Android进阶(一)-------Android中AsyncTask的简单用法

随机推荐

  1. Android设计模式系列(0)--开篇
  2. 深入Android(安卓)【一】 —— 序及开篇
  3. Android(安卓)系统启动流程简析
  4. Android的init过程详解(一)
  5. 第十二章:Android数据存储(下)
  6. 如果没有 Android,世界会怎样?
  7. Android(安卓)设备管理API概览(Device Adm
  8. Android(安卓)Handler机制
  9. Android在未来的发展
  10. 使用android中drawline函数无法绘制水平