Handler介绍
只有创建控件的UI主线程才能去更新该控件的内容。
所有的UI线程要去负责View的创建并且维护它,都必须在UI主线程中去做。如果子线程想更新UI咋办?Handler是一种不错的处理方式。
这里很不厚道(反正脸早就丢完了)的偷了张图片来, 这个图片内容 介绍的有些问题,但大体思路是正确的。

图中存在的问题:那不叫消息队列,应该叫消息链表(那里面按时间进行了插入操作,怎么可能叫队列)
其它问题暂时不提。
1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
每个线程只有一个Looper,它负责管理MessageQueue,会不断地从MessageQueue取出消息,并将消息分给对应的Hanlder处理。
2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
3) Message Queue(消息队列):用来存放线程放入的消息。
4)线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
5)Android规定:只允许UI线程修改Activity里的UI组建。 因为UI的操作并不是线程安全的。为了不阻塞主线程,所以就这么规定了。
UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个
线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。
1、Android的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper。主线程(UI线程)就是一个消息循环的线程。
2、获取looper:
Looper.myLooper(); //获得当前的Looper
Looper.getMainLooper() //获得UI线程的Lopper
3、Handle的初始化函数(构造函数),如果没有参数,那么他就默认使用的是当前的Looper,如果有Looper参数,就是用对应的线程的Looper。
4、如果一个线程中调用Looper.prepare(),那么系统就会自动的为该线程建立一个消息队列,然后调用 Looper.loop();之后就进入了消息循环,这个之后就可以发消息、取消息、和处理消息。
Looper是每条线程里的Message Queue的管家。Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper() 得到当前线程的Looper就有可能为NULL。
Handler类包含如下方法用于发送、处理消息:
-
void handleMessage(Message msg):处理消息的方法,该方法通常用于被重写。
-
final boolean hasMessage(int what):检查消息队列是否包含what属性指定值的消息。
-
final boolean hasMessage(int what,Object object):检查消息队列中是否包含what属性为指定且object属性为指定指定对象的消息。
-
Message obtainMessage():获取消息。
-
sendEmptyMessage(int what):发送空消息。
-
final boolean sendEmptyMessageDelayed(int what,long delayMillis):指定多少毫秒之后发送空消息。
-
final boolean sendMessage(Message msg):立即发送消息。
-
final boolean sendMessageDelayed(Message msg,long delayMillis):指定多少毫秒之后发送消息。
如果你不带参数的实例化:Handler handler = new Handler();那么这个会默认用当前线程的looper
一般而言,如果你的Handler是要来刷新操作UI的,那么就需要在主线程下跑。
Message是线程之间传递信息的载体,包含了对消息的描述和任意的数据对象。Message中包含了两个额外的 int字段和一个object字段,这样在大部分情况下,使用者就不需要再做内存分配工作了。虽然Message的构造函数是public的,但是最好是 使用Message.obtain( )或Handler.obtainMessage( )函数来获取Message对象,因为Message的实现中包含了回收再利用的机制,可以提供效率。
-------------------------------------------------------------------------
1.Message
消息对象,顾名思义就是记录消息信息的类。这个类有几个比较重要的字段
a.arg1和arg2:我们可以使用两个字段用来存放我们需要传递的整型值,在Service中,我们可以用来存放Service的ID。
b.obj:该字段是Object类型,我们可以让该字段传递某个多项到消息的接受者中。
c.what:这个字段可以说是消息的标志,在消息处理中,我们可以根据这个字段的不同的值进行不同的处理,类似于我们在处理Button事件时,通过switch(v.getId())判断是点击了哪个按钮。
在使用Message时,我们可以通过new Message()创建一个Message实例,但是Android更推荐我们通过Message.obtain()或者Handler.obtainMessage()获取Message对象。这并不一定是直接创建一个新的实例,而是先从消息池中看有没有可用的Message实例,存在则直接取出并返回这个实例。反之如果消息池中没有可用的Message实例,则根据给定的参数new一个新Message对象。通过分析源码可得知,Android系统默认情况下在消息池中实例化10个Message对象。
2.MessageQueue
消息队列,用来存放Message对象的数据结构,按照“先进先出”的原则存放消息。存放并非实际意义的保存,而是将Message对象以链表的方式串联起来的。MessageQueue对象不需要我们自己创建,而是有Looper对象对其进行管理,一个线程最多只可以拥有一个MessageQueue。我们可以通过Looper.myQueue()获取当前线程中的MessageQueue。
3.Looper
MessageQueue的管理者,在一个线程中,如果存在Looper对象,则必定存在MessageQueue对象,并且只存在一个Looper对象和一个MessageQueue对象。在Android系统中,除了主线程有默认的Looper对象,其它线程默认是没有Looper对象。如果想让我们新创建的线程拥有Looper对象时,我们首先应调用Looper.prepare()方法,然后再调用Looper.loop()方法。
一个子线程如何使用消息机制
public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }

浙公网安备 33010602011771号