介绍
- 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在哪个线程定义,而looper特殊传入的话,则回调在哪个线程,所以在主线程的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还没有创建成功,而出现没有looper的问题。这时候需要使用handlerThread。handlerThread使用了wait来等待looper的创建。
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;
}
}
}
网友评论