介绍
-
Message
消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。 -
Message Queue
消息队列,用来存放通过Handler发布的消息,按照先进先出执行。 -
Handler
有俩用途:1、用于子线程与主线程之间的通讯 2、用于向子线程发出消息请求。Handler是Message的主要处理者,是Android提供的一套ui处理机制,负责将Message添加到消息队列以及对消息队列中的Message进行处理。 -
Looper
循环器,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理。 -
线程
UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。
异常
-
Only the original thread that created a view hierarchy can touch its views.
这个异常就是在子线程中进行更新ui操作抛出的,android的设计的时候,就封装了一套消息创建、传递、处理机制。比如我们不按要求在子线程去更新ui的话就会抛出以上异常。不过我们看一下下面的代码:
public class MyActivity extends Activity { private TextView tvText; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvText = (TextView) findViewById(R.id.main_tv); new Thread(new Runnable() { @Override public void run() { tvText.setText("OtherThread"); } }).start(); } }
我们知道这段代码中在子线程进行了ui的操作,不过我们的代码是可以运行的,我们看一下定义异常的地方就知道了。
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { ………………………… void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); } } …………………… }
setText在源码中会调用checkforlayout方法然后invalidate。然后在checkThread里面判断thread和uiThread是否相等然后抛异常。
不能更新ui是因为ViewRootImpl的checkThread()的检查,而ViewRootImpl是在onResume()的方法中创建的,所以在onCreate中没有穿件ViewRootImpl,所以不抛异常,如果耗时的话才会抛出异常。比如我们在setText前面加上一个延迟。
- 内存泄漏
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHandler.sendMessageDelayed(Message.obtain(), 10000); finish(); }
为什么会泄漏?
Handler 的生命周期与Activity 不一致;
引用 Activity 阻止了GC对Acivity的回收。
如何防止?
静态内部类,外部类
WeakReference
private static class MyHandler extends Handler{ }
然后
mHandler.removeCallbacks(mRunnable); //或者 mHandler.removeCallbacksAndMessages(null);
用法
-post
private Handler handler = new Handler(); new Thread(new Runnable() { @Override public void run() { handler.post(new Runnable() { @Override public void run() { } })) } }).start(); 这里直接使用的post进行处理,run回调下可以进行ui更新,更加轻便,postDelay还可以实现延迟效果。
-sendMessage
Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; 这里使用了handlerMessage的回调,通过msg来传递信息,更加实用。
Message message = new Message(); handler.sendMessage(message);
Message msg = mHandler.obtainMessage(); msg.sendToTarget();
obtainmessage()是从消息池中拿来一个msg 不需要另开辟空间;
new需要重新申请,效率低,obtianmessage可以循环利用;
removeCallback 从队列中移除消息。
子线程间的通讯
在子线程中使用时需要手动添加代码loop,主线程其实也需要,只不过我们的android架构已经帮我们实现了。
handler与子线程的关联:
class Thread extends Thread{ public Handler handler; @Override public void run(){ Looper.prepare(); handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; Looper.loop(); } }
private MyThread thread; thread = new MyTread(); thread.start(); thread.handler.sendEmptyMessage();
handler在哪个线程定义,则回调在哪个线程,所以在主线程的handlerMessage不要进行耗时处理。
handlerThread
在子线程定义thead
class Thread extends Thread{ public Handler handler; public Looper looper; @Override public void run(){ Looper.prepare(); looper = Looper.myLooper(); handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; Looper.loop(); } }
将loop传递进来:
Handler handler = new Handler(thread.looper){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; handler.sendEmptyMessage();
这里涉及到了一个多线程并发的问题,我们主线程中new Handler()中使用looper而子线程中looper还没有创建成功。这时候需要使用handlerThread。
thread = HandlerThread("handler thread"); thread.start();
handler = new Handler(thread.getlooper()){ public void handlerMessage(android.os.Message msg){ } } handler.sendEmptyMessage();
用handlerthread线程的话,可以等待looper实例创建好再发送。
子线程主线程通讯
Handler threadHandler; Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); threadHandler.sendMessageDelayed(msg1,1000); } };
HandlerThread thread = new HandlerThread("handler thread"); thread.start(); threadHandler = new Handler(thread.getlooper()){ @Override public void handleMessage(android.os.Message msg){ handler.sendMessageDelayed(msg1,1000); } }
更新ui的方式
- handler.post
- sendMessage
- runOnUiThread
-
view.post
这个很实用比如某些动画需要实现,而view没有初始化成功导致动画或者其他效果失效,这里可以使用这个方法。
WeakHandler
weakHandler是一个避免内存泄漏的handler库,使用方法和handler基本一致,但是我们要理解一下weakReference,就是弱引用,我们知道java中我们开发人员虽然不需要在意内存回收,可是在使用方面可以做到尽可量的优化,在我们使用弱引用的时候,我们的这个对象,如果他没有没其他对象引用,就会被gc,反着如果强引用的话就不会gc了。
这里我们拓展一下:
-
强引用(StrongReference)
只要引用存在,垃圾回收器永远不会回收,也是我们默认的引用。 -
软引用(SoftReference)
非必须引用,内存溢出之前进行回收。 -
弱引用(WeakReference)
谷歌更推荐这个使用,这个在垃圾搜索器搜索到这个对象时就会进行回收。
软引用和弱引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。 -
虚引用(PhantomReference)
虚引用用处不详..我理解为gc时候就会把虚引用一起回收了。
总结为,强引用只要有引用就绝不回收,弱引用是oom前,软引用是垃圾回收的时候回收。
这里再介绍一个消息通知的框架 可以用于换肤等:
public class UIMessageCenter { private final static int UI_MSG_CHANFE_SKIN = 1; private static UIMessageCenter Intance = null; private List<WeakReference<IonMessage>> mOnMsgList = null; private WeakHandler mHanderUI = null; private UIMessageCenter() { mOnMsgList = new ArrayList<WeakReference<IonMessage>>(); createHandler(); } public static UIMessageCenter getIntance() { if (Intance == null) { Intance = new UIMessageCenter(); } return Intance; } private void createHandler() { mHanderUI = new WeakHandler() { @Override public void handleMessage(Message msg) { if (mOnMsgList != null && mOnMsgList.size() > 0) { for (int i = 0; i < mOnMsgList.size(); i++) { WeakReference<IonMessage> fun = mOnMsgList.get(i); if (fun != null) { IonMessage ionMsg = fun.get(); if (ionMsg != null) { HttpLog.d("handleMessage", "createHandler"); ionMsg.onMessage(msg); } } } } } }; } public void registerFun(IonMessage fun) { if (mOnMsgList != null && fun != null) { mOnMsgList.add(new WeakReference<IonMessage>(fun)); } } public void removeFun(IonMessage fun) { if (mOnMsgList != null && fun != null) { mOnMsgList.remove(new WeakReference<IonMessage>(fun)); } } /** * 通知换肤 * * @param arg1 * @param arg2 * @param obj */ public void notifyChangeSkin(int arg1, int arg2, Object obj) { if (mHanderUI != null) { mHanderUI.sendMessage(mHanderUI.obtainMessage(UI_MSG_CHANFE_SKIN, arg1, arg2, obj)); } } }
public interface IonMessage { void onMessage(Message msg); }
使用方法:
class MyActivity extend Activity implements IonMessage{ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); UIMessageCenter.getIntance().registerFun(this); } @Override public void onDestroy() { super.onDestroy(); UIMessageCenter.getIntance().removeFun(this); } @Override public void onMessage(Message msg) { switch (msg.what) { case UIMessageCenter.UI_MSG_CHANFE_SKIN: changeSkin(); break; default: break; } } }
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。