Android消息机制

在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()); 
}


Looper private的构造器:

final MessageQueue mQueue;
private Looper() {
	mQueue = new MessageQueue();
	mRun = true;
	mThread = Thread.currentThread();
}

Looper初始化的时候,会初始化本线程对应的MessageQueue。


Lopper.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    
                       );    
               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();    
           }    
       }    
   }


msg.target是生成消息 的handler对象,表示需要处理这个消息的handler对象。Handler的void dispatchMessage(Message msg)方法见下节。

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一一关联的对象,通过消息队列机制对消息进行存储。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值