Handler消息机制
2018-03-07 14:48
169 查看
Handler消息机制
@(Android)Handler消息机制是Android系统提供的一种用于解决线程间通信的方式。Handler主要作用,分发和处理消息,实现将一个任务切换到指定的线程中执行。
为什么使用Handler?
子线程是无法访问UI的。如果允许子线程访问UI且存在并发的情况,会使得控件处于混乱的状态。如果采用加锁来解决并发问题,又会使UI访问的效率降低。因此Android采用单线程模型操作UI,通过handler切换到UI线程,解决子线程无法访问UI的问题。理解handler,Message,MessageQueue及Looper四者关系,是搞懂Android消息机制的关键。
Message
Message是消息机制中的媒介,包含了描述和任意数据对象,用于发送给handler。handler.postXXX(Runnable r)底层也是将Runnable封装成一个Message,这个Runnable设为Message的callback属性。public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
MessageQueue
MessageQueue是一个单链表,用于存放所有handler发送过来的消息。enqueueMessage( )往队列中插入一条消息,next( )是一个无限循环的方法,用于移除消息,如果队列为空,则阻塞。Looper
Looper是给线程轮询消息的。线程默认是没有Looper的,需要调用Looper.prepare()创建looper,使用Looper.loop()开启消息循环,将next()获取的消息通msg.target.dispatchMessage(msg)回调给handler。如果线程中没有创建Looper,是无法使用handler的。由于Android程序在其入口函数ActivityThread$main(),调用了 Looper.prepareMainLooper(),因此我们可以在主线程中直接使用Handler。一个线程中只能有一个MessageQueue和Looper,采用ThreadLocal进行保存
Handler
Looper把消息回调到handler的dispatchMessage中进行消息处理:若该消息有callback,即通过Post(Runnable)的方式投递消息,因为在投递runnable时,把runnable对象赋值给了message的callback。
若handler的mCallback不为空,则交由通过callback创建handler方式去处理。
否则,由最常见创建handler对象的方式,在重写handlerMessage中处理。
子线程中使用Handler
遵循三个步骤- 创建Looper
- 调用Looper.loop()
- 创建Handler
public class ChildThreadHandlerActivity extends Activity { private MyThread childThread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler); childThread = new MyThread(); childThread.start(); Handler childHandler = new Handler(childThread.childLooper){//这样之后,childHandler和childLooper就关联起来了。 public void handleMessage(Message msg) { }; }; } private class MyThread extends Thread{ public Looper childLooper; @Override public void run() { Looper.prepare();//创建与当前线程相关的Looper childLooper = Looper.myLooper();//获取当前线程的Looper对象 Looper.loop();//调用此方法,消息才会循环处理 } } }
创建子线程的handler, Handler childHandler = new Handler(childThread.childLooper)后,就可以使用这个childHandler发送消息到子线程中执行。上述代码中由于多线程,childThread.childLooper可能回报空指针错误。
Android提供HandlerThread,简化子线程使用Handler的代码。HandlerThread的run方法中创建Looper,并开启消息循环loop(),
@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; }
getLooper()中使用wait,以及run()中使用nitifyAll(),解决getLooper()可能为空的问题。
HandlerThread应用示例
public class HandlerThreadActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler); TextView textView = (TextView) findViewById(R.id.tv); textView.setText("HandlerThreadActivity.class"); HandlerThread handlerThread = new Ha 4000 ndlerThread("HandlerThread"); handlerThread.start(); Handler mHandler = new Handler(handlerThread.getLooper()){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.d("HandlerThreadActivity.class","uiThread2------"+Thread.currentThread());//子线程 } }; Log.d("HandlerThreadActivity.class","uiThread1------"+Thread.currentThread());//主线程 mHandler.sendEmptyMessage(1); } }
子线程如何切换到UI线程
创建主线程的handler,并发送消息new Handler(getMainLooper()).post(new Runnable() { @Override public void run() { // 将在UI线程执行下句 Toast.makeText(getApplicationContext(), "Loaded Person from broadcast-receiver->intent-service: " + info, Toast.LENGTH_LONG).show(); } });
Activity的runOnUiThread和View.postDelayed()内部也是使用handler切换到UI线程执行自己的Runnable。
public final void runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); } }
public boolean postDelayed(Runnable action, long delayMillis) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { return attachInfo.mHandler.postDelayed(action, delayMillis); } // Assume that post will succeed later ViewRootImpl.getRunQueue().postDelayed(action, delayMillis); return true; }
Handler要注意的坑
使用非静态内部类声明Handler,会造成内存泄漏,推荐静态内部类+弱引用。onDestory中移除队列中的消息,handler.removeCallbacksAndMessages(null)。
al-and-quick-reference
相关文章推荐
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- 【Android自助餐】Handler消息机制完全解析(五)鸟瞰与总结
- handler消息传递机制
- Toast和Looper,Handler消息循环机制
- Android消息处理机制(Handler、Looper、MessageQueue与Message)
- Android消息机制中Handler切换线程的思考记录
- 安卓中的消息循环机制Handler及Looper详解
- 面试题之--Handler-消息机制
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- handler——子线程中创建消息处理机制
- 消息机制,Handler
- 消息机制--Message.Handler与Looper(1)
- Android 消息机制——你真的了解Handler?
- Handler, Message 消息传递机制
- Android消息处理机制Thread、Handler、Looper 分类: Android 2015-07-15 09:28 5人阅读 评论(0) 收藏
- Android消息机制(Handler,Looper,MessageQueue)-源码分析
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
- android中的消息机制 了解Handler
- 浅析Android消息处理机制--Handler And Looper
- Handler消息机制源码解析(一)