标签:
我为什么写Handler,原因主要还在于它在整个 Android 应用层面非常之关键,他是线程间相互通信的主要手段。最为常用的是其他线程通过Handler向主线程发送消息,更新主线程UI。
下面是一个最简单的例子。
1 import android.os.Handler; 2 import android.os.Message; 3 import android.support.v7.app.AppCompatActivity; 4 import android.os.Bundle; 5 import android.widget.TextView; 6 7 public class MainActivity extends AppCompatActivity { 8 9 private TextView myTextView; 10 private Handler myHandler = new Handler(){ 11 @Override 12 public void dispatchMessage(Message msg) { 13 //UI线程接收到消息 14 int arg1 = msg.arg1; 15 switch (arg1){ 16 case 0: 17 if(msg.arg2 == 0){ 18 //更新UI 19 myTextView.setText((String)msg.obj); 20 } 21 break; 22 default: 23 break; 24 } 25 super.dispatchMessage(msg); 26 } 27 }; 28 @Override 29 protected void onCreate(Bundle savedInstanceState) { 30 super.onCreate(savedInstanceState); 31 setContentView(R.layout.activity_main); 32 myTextView = (TextView)this.findViewById(R.id.text_view); 33 //起独立线程 34 new Thread(){ 35 public void run(){ 36 String text = "from handler"; 37 Message message = new Message(); 38 message.arg1 = 0; 39 message.arg2 = 0; 40 message.obj = text; 41 //通过Handler给UI发消息 42 myHandler.sendMessage(message); 43 } 44 }.start(); 45 } 46 }
上面的例子看似好简单了。但是支持这样消息从一个线程传到另一个线程,不仅仅需要Handler这样一个类的支持,还需要其他类的支持,分别是 Looper, Message, MessageQueue。
消息流转的组件:
Message 是消息的实体。
MessageQueue 时消息队列。
Looper 每一个线程只有一个,它做两件事:
一件是将创建一个MessageQueue,提供给Handler将message添加到MessageQueue里面。
另一件是不同的轮询从MessageQueue里面读取Message传递给Handler的dispatchMessage(message)进行处理。
消息的流转
第一步,需要接受消息的线程需要和Looper绑定。Activity(UI线程)启动的时候本身就会创建自己的Looper,而创建new Looper()里面MesssageQueue对象被创建。UI线程的绑定则是在new Handler()方法中获取UI线程Looper。非UI线程启用Looper的时候需要调用Looper.prepare()进行Looper对象的初始化(注,初始化只能调用一次)。 在初始化Looper对象的时候,MessageQueue对象被同时创建。
public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } //获取该线程的Looper对象。 mLooper = Looper.myLooper(); mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
第二步,通过Handler发送消息,即sendMessage(message)等其他类似方法。这些方法最后都调用到了MessageQueue的enqueueMessage(...),将消息添加到消息队列中。
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; //msg被添加到MessageQueue对象queue中。 return enqueueMessage(queue, msg, uptimeMillis); }
第三步,Looper轮询将消息从MessageQueue中获取出来。具体的方法是Looper.loop(),该方法最后调用到了msg.target.dispatchMessage(message),其中msg.target就是message对象的发送者Handler对象。Looper.loop()该方法是通过获取到looper对象,进一步获取到looper对象里面的MessaageQueue。然后轮询该MessageQueue里面的消息,直到消息为空。
public static void loop() { //获取loop final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread."); } //获取loop里面的MessageQueue对象 final 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(); //无限循环获取消息 for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; //有消息则调用handler的dispatchMessage msg.target.dispatchMessage(msg); // Make sure that during the course of dispatching the // identity of the thread wasn‘t corrupted. final long newIdent = Binder.clearCallingIdentity(); msg.recycle(); } }
第四步,处理消息,调用dispatchMessage(Message)方法。不必细说。
在以上过程中需要注意一下。
Message对象本身存在于一个消息池中。如果消息池中有消息,建议不要使用new的方式产生对象应该服用该对象
Message message = myHandler.obtainMessage(); message.arg1 = 0; myHandler.sendMessage(message);
今天就到这吧。这只是一部分,明天再说另一部分。同样的作为进程间通信的开源组件EventBus也将被分析。
标签:
原文地址:http://www.cnblogs.com/ouyanliu/p/5735032.html