Android消息机制
来源:互联网 发布:汗脚引起灰指甲知乎 编辑:程序博客网 时间:2024/04/27 20:38
在Android中,主线程UI线程不是线程安全的,对UI的更新只能在UI线程中执行,在工作线程中执行UI更新操作,会抛出android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 错误。
为了实现工作线程对UI线程的操作,以及线程间通信,Android中设计了一套消息机制。
Android消息机制主要有Looper、Handler、Message和MessageQueue几个类组成。
借用下别人的图片,各组件的关系如下:
Looper
每个线程只能有一个Looper(其实Looper是一个ThreadLocal对象),Looper主要实现对MessageQueue中的Message信息的消费。
UI线程启动的时候,默认绑定了一个Looper。
对于工作线程可通过Looper.prepare()和Looper.loop()简单的两步,把线程变为LooperThread,实现线程对消息的消费。并为工作线程实例化Handler对象,用于消息的发送和处理。
Looper.prepare()静态方法:
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()); }
final MessageQueue mQueue;private Looper() {mQueue = new MessageQueue();mRun = true;mThread = Thread.currentThread();}
Looper初始化的时候,会初始化本线程对应的MessageQueue。
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(); } } }
Looper可以通过静态方法getMainLooper()获取UI线程的Looper对象,通过静态方法myLooper(),获取本线程的Looper对象。
Handler
Handler负责对信息的发送和处理,工作线程可以引用UI线程的Handler实例对象,通过post、postDelayed和sendMessage方法,把消息发送到MessageQueue中。
其中post*方法,传递的为Runnable对象,Runnable对象被封装为Message的callback属性,所以最终发送到MessageQueue中的还是Message对象。
Handler通过覆复写handleMessage方法,作为处理Message的回调方法,实现对Message的处理。
消息处理步骤:
- Looper在消费Message的时候,先判断Message中是否有callback方法,如果有,调用callback,处理消息。
- 如果Handler中有mCallback方法,则调用该方法处理消息。
- 否则,调用handleMessage方法处理消息。
一个线程可以有多个Handler对象,同一个Handler对象发送的Message,由对象自身的handleMessage方法进行处理。
handler.despatchMessage实例方法:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
在工作线程中,需要向UI线程发送消息是,不一定要在UI线程中建立Handler对象,并传递到工作现在。
在工作线程中,可以通过Looper.getMainLooper()获取到UI线程的Looper对象,并通过此Looper对象,实例化Handler对象,绑定到UI线程的Looper和MessageQueue。
class MyThread extends Thread{ public void run(){ Looper looper = Looper.getMainLooper(); //主线程的Looper对象 //这里以主线程的Looper对象创建了handler, //所以,这个handler发送的Message会被传递给主线程的MessageQueue。 handler = new MyHandler(looper); //构建Message对象 //第一个参数:是自己指定的message代号,方便在handler选择性地接收 //第二三个参数没有什么意义 //第四个参数需要封装的对象 Message msg = handler.obtainMessage(1,1,1,"其他线程发消息了"); handler.sendMessage(msg); //发送消息 } }
Message
Message是消息的载体,Message中有String arg1、String arg2、Object obj、int what等几个属性,用户传递简单参数。复杂参数则使用Bundle传递。
Message可以通过静态方法Message.obtain()和实例方法handler.obtainMessage()等方法获取,可以实现对Message对象的复用。通过实例方法message.cycle(),实现Message的回收复用。
实例方法message.sendToTarget()方法等同于实例方法handler.sendMessage()
MessageQueue
MessageQueue是和Looper一一关联的对象,通过消息队列机制对消息进行存储。
- Android消息机制(Handler机制)
- android Handler机制 消息机制
- Android 消息处理机制
- Android消息机制
- android 消息机制
- Android消息机制(一)
- Android消息处理机制
- Android消息处理机制
- Android消息机制(一)
- Android 中的消息机制
- Android 消息通知机制
- Android消息机制学习
- Android消息机制(1)
- Android消息机制
- android消息机制
- Android消息机制
- Android的消息机制
- android消息处理机制
- css相对定位绝对定位和内容居中详解
- 专业英语继续
- 数塔问题
- 读面向业务的立体化高可用架构总结
- 数据的交换输出
- Android消息机制
- struts2中使用到的一部分jar包
- 某一常见电脑病毒的剖析
- 加密的世界
- Android按下返回键后,程序不退出,进入后台运行。使用moveTaskToBack(boolean nonRoot)
- Android完整的app项目
- (PHP)正则表达式-preg_grep函数用法
- struts.xml配置详解
- Sublime 支持中文