Handler使用
hander的使用
方法一
1、在New Handler的时候传入Handler.Callback对象,Handler.Callback中,并实现Handler.Callback的handleMessage方法
2、mHandler.sendMessageAtTime使用
mHandler = new Handler(new MandlerCallback());
mHandler.sendEmptyMessage(1);
private class MandlerCallback implements Handler.Callback{
@Override
public boolean handleMessage(Message message) {
switch(message.what){
case 1:
switchText.setText("change 1");
break;
}
return false;
}
}
方法二
1、无需向Hanlder的构造函数传入Handler.Callback对象,但是需要重写Handler本身的handleMessage方法
devicehandler = new DevicegetHandler();
devicehandler.sendEmptyMessage(MSG_DEVICE_UPDATE);
private final class DevicegetHandler extends Handler {
public DevicegetHandler(){
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DEVICE_UPDATE:
xxx
break;
default:
break;
}
}
}
方法三 子线程
注意下面的代码存在问题,有时能运行,有时会奔溃
TestThread mmm = new TestThread();
mmm.start(); // 必须先启动在绑定给Looper
mHandler = new Handler(mmm.mLooper){
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
Log.d(TAG,"test hander message");
break;
default:
break;
}
}
};
private class TestThread extends Thread{
public Looper mLooper;
@Override
public void run() {
//super.run();
Looper.prepare();
mLooper = Looper.myLooper();
Log.d(TAG,"TestThread run");
Looper.loop();
}
}
new Handler(childThread.childLooper)的时候,run方法中的Looper对象还没初始化
修正方法1 提前执行Thread
private TestThread mmm;
onCreate(){
mmm = new TestThread();
mmm.start(); // 必须先启动在绑定给Looper
}
other(){
if(mmm.mLooper != null){
mHandler = new Handler(mmm.mLooper){
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
Log.d(TAG,"test hander message");
//注意这里不能做ui更新
break;
default:
break;
}
}
};
}
}
修正方法2 --使用系统的HandlerThread
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
mkHandler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG,"uiThread2------"+Thread.currentThread());//子线程
}
};
Log.d(TAG,"uiThread1------"+Thread.currentThread());//主线程
Handler 内存泄露
使用Handler导致内存泄露的解决方法
方法一:通过程序逻辑来进行保护。
1.在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。
2.如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。
方法二:将Handler声明为静态类。
PS:在Java 中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用,静态的内部类不会持有外部类的引用。
静态类不持有外部类的对象,所以你的Activity可以随意被回收。由于Handler不再持有外部类对象的引用,导致程序不允许你在Handler中操作Activity中的对象了。所以你需要在Handler中增加一个对Activity的弱引用(WeakReference)。
方法一代码:
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
mkHandler.removeCallbacksAndMessages(handlerThread);
}
方法二代码:
public class NoLeakActivity extends AppCompatActivity {
private NoLeakHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new NoLeakHandler(this);
Message message = Message.obtain();
mHandler.sendMessageDelayed(message,10*60*1000);
}
private static class NoLeakHandler extends Handler{
private WeakReference<NoLeakActivity> mActivity;
public NoLeakHandler(NoLeakActivity activity){
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
}
注意通过该mActivity.get().去获取acitivity
private TextView switchText;
onCreate(){
mHandler = new MandlerCallback(this);
switchText = (TextView)findViewById(R.id.switchText);
}
private static class MandlerCallback extends Handler{
private WeakReference<mmmm> mActivity;
public MandlerCallback(mmmm activity){
this.mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message message) {
switch(message.what){
case 1:
mActivity.get().switchText.setText("change 2");
break;
}
}
}
原理
源码
frameworks/base/core/java/android/os/Handler.java