handler——Handler详解

来源:互联网 发布:收集区域手机号码软件 编辑:程序博客网 时间:2024/06/05 04:06

转自http://www.jb51.net/article/33514.htm

handler扮演了往MQ上添加消息和处理消息的角色(只处理由自己发出的消息),即通知MQ它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。handler创建时会关联一个looper,默认的构造方法将关联当前线程的looper,不过这也是可以set的。默认的构造方法:

publicclass handler {final MessageQueue mQueue; // 关联的MQfinal Looper mLooper; // 关联的looperfinal Callback mCallback;// 其他属性public Handler() {// 没看懂,直接略过,,,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());}}// 默认将关联当前线程的loopermLooper = Looper.myLooper();// looper不能为空,即该默认的构造方法只能在looper线程中使用if (mLooper ==null) {thrownew RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}// 重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上mQueue = mLooper.mQueue;mCallback =null;}// 其他方法} 

在子线程中加入

publicclass LooperThread extends Thread {private Handler handler1;private Handler handler2;@Overridepublicvoid run() {// 将当前线程初始化为Looper线程Looper.prepare();// 实例化两个handlerhandler1 =new Handler();handler2 =new Handler();// 开始循环处理消息队列Looper.loop();}} 

加入handler后的效果如下图:


可以看到,一个线程可以有多个Handler,但是只能有一个Looper!

有了handler之后,我们就可以使用 post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long)和 sendMessageDelayed(Message, long)这些方法向MQ上发送消息了。光看这些API你可能会觉得handler能发两种消息,一种是Runnable对象,一种是message对象,这是直观的理解,但其实post发出的Runnable对象最后都被封装成message对象了,见源码:

// 此方法用于向关联的MQ上发送Runnable对象,它的run方法将在handler关联的looper线程中执行publicfinalboolean post(Runnable r){// 注意getPostMessage(r)将runnable封装成messagereturn sendMessageDelayed(getPostMessage(r), 0);}privatefinal Message getPostMessage(Runnable r) {Message m = Message.obtain(); //得到空的messagem.callback = r; //将runnable设为message的callback,return m;}publicboolean sendMessageAtTime(Message msg, long uptimeMillis){boolean sent =false;MessageQueue queue = mQueue;if (queue !=null) {msg.target =this; // message的target必须设为该handler!sent = queue.enqueueMessage(msg, uptimeMillis);}else {RuntimeException e =new RuntimeException(this+" sendMessageAtTime() called with no mQueue");Log.w("Looper", e.getMessage(), e);}return sent;} 


其他方法就不罗列了,总之通过handler发出的message有如下特点:
1.message.target为该handler对象,这确保了looper执行到该message时能找到处理它的handler,即loop()方法中的关键代码

msg.target.dispatchMessage(msg);


2.post发出的message,其callback为Runnable对象


Handler处理消息

说完了消息的发送,再来看下handler如何处理消息。消息的处理是通过核心方法dispatchMessage(Message msg)与钩子方法handleMessage(Message msg)完成的,见源码

// 处理消息,该方法由looper调用publicvoid dispatchMessage(Message msg) {if (msg.callback !=null) {// 如果message设置了callback,即runnable消息,处理callback!handleCallback(msg);} else {// 如果handler本身设置了callback,则执行callbackif (mCallback !=null) {/* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。见http://alex-yang-xiansoftware-com.iteye.com/blog/850865 */if (mCallback.handleMessage(msg)) {return;}}// 如果message没有callback,则调用handler的钩子方法handleMessagehandleMessage(msg);}}// 处理runnable消息privatefinalvoid handleCallback(Message message) {message.callback.run(); //直接调用run方法!}// 由子类实现的钩子方法publicvoid handleMessage(Message msg) {} 

可以看到,除了handleMessage(Message msg)和Runnable对象的run方法由开发者实现外(实现具体逻辑),handler的内部工作机制对开发者是透明的。这正是handler API设计的精妙之处!


Handler的用处

1.handler可以在任意线程发送消息,这些消息会被添加到关联的MQ上。



2.handler是在它关联的looper线程中处理消息的。




这就解决了android最经典的不能在其他非主线程中更新UI的问题。android的主线程也是一个looper线程(looper 在android中运用很广),我们在其中创建的handler默认将关联主线程MQ。因此,利用handler的一个solution就是在 activity中创建handler并将其引用传递给worker thread,worker thread执行完任务后使用handler发送消息通知activity更新UI。(过程如图)

下面给出sample代码,仅供参考

publicclass TestDriverActivity extends Activity {private TextView textview;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);textview = (TextView) findViewById(R.id.textview);// 创建并启动工作线程Thread workerThread =new Thread(new SampleTask(new MyHandler()));workerThread.start();}publicvoid appendText(String msg) {textview.setText(textview.getText() +"\n"+ msg);}class MyHandler extends Handler {@Overridepublicvoid handleMessage(Message msg) {String result = msg.getData().getString("message");// 更新UIappendText(result);}}} 

publicclass SampleTask implements Runnable {privatestaticfinal String TAG = SampleTask.class.getSimpleName();Handler handler;public SampleTask(Handler handler) {super();this.handler = handler;}@Overridepublicvoid run() {try { // 模拟执行某项任务,下载等Thread.sleep(5000);// 任务完成后通知activity更新UIMessage msg = prepareMessage("task completed!");// message将被添加到主线程的MQ中handler.sendMessage(msg);} catch (InterruptedException e) {Log.d(TAG, "interrupted!");}}private Message prepareMessage(String str) {Message result = handler.obtainMessage();Bundle data =new Bundle();data.putString("message", str);result.setData(data);return result;}} 
当然,handler能做的远远不仅如此,由于它能post Runnable对象,它还能与Looper配合实现经典的Pipeline Thread(流水线线程)模式。请参考此文《Android Guts: Intro to Loopers and Handlers》


0 0
原创粉丝点击