本文主要是介绍Android中Handler使用不当引起的内存泄露,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
通常我们在Android编程中,常常会用到它自己提供的一种异步回调机制Handler,通过它,我们可以在进行异步操作后处理返回结果,通常我们的代码是这么实现的:在主线程中,new一个Handler对象实现其handleMessage方法,在handleMessage中提供收到消息后的相应处理的方法即可,示例代码如下:
package com.tb.demo.utils.hangview;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
/**
* Created by tb
*/
public class DemoHandlerActivity extends Activity {
private final int LOADDBDATA = 0x1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getLocalData();
}
/**
* 获取本地数据
*/
private void getLocalData() {
//start get data from db
//do something
//...
//...
//end get data from db
handler.sendEmptyMessage(LOADDBDATA);
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case LOADDBDATA:
// do something when msg.what=0x01
// ...
// ...
break;
default:
break;
}
}
};
}
然而写完这个Handler之后Android Studio报了一个警告,如下图:
解释如下:
1.当这个App启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper负责管理MessageQueue和Message对象,读取到MessageQueue中的Message之后就会采用sendMessage的方式把消息发送给对应的Handler来处理,Looper接收到一条一条的消息后逐一进行处理,所以主线程中的Looper和App的生命周期一样长。
2.当一个Handler在主线程进行了初始化之后,我们发送一个target为这个Handler的消息到Looper处理的消息队列时,实际上已经发送的消息包含了一个Handler实例的引用,只有这样Looper在处理到这条消息时才可以调用 Handler#handleMessage(Message)完成消息的正确处理。
3.在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用。静态的内部类不会持有外部类的引用。
解决思路:
不使用非静态内部类,继承Handler时,或者放在单独的类文件中,或者使用静态内部类。因为静态的内部类不会持有外部类的引用,所以不会导致外部类实例的内存泄露。当你需要在静态内部类中调用外部的Activity时,我们可以使用弱引用来处理。注意:一个静态的匿名内部类实例不会持有外部类的引用。
调整代码如下:
package com.tb.demo.utils.hangview;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import java.lang.ref.WeakReference;
/**
* Created by tangbin on 15/9/5.
*/
public class DemoHandlerActivity extends Activity {
private MyHandler myHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myHandler = new MyHandler(this);
getLocalData();
}
/**
* 获取本地数据
*/
private void getLocalData() {
// start get data from db
// do something
// ...
// ...
// end get data from db
myHandler.sendEmptyMessage(myHandler.LOADDBDATA);
}
public void logOut() {
System.out.println("data is ok");
}
/**
* Instances of static inner classes do not hold an implicit reference to
* their outer class.
*/
static class MyHandler extends Handler {
public static final int LOADDBDATA = 0x1;
WeakReference<DemoHandlerActivity> activity;
MyHandler(DemoHandlerActivity mActivity) {
activity = new WeakReference<DemoHandlerActivity>(mActivity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
DemoHandlerActivity ac = activity.get();
switch (msg.what) {
case LOADDBDATA:
// do something when msg.what=0x01
// ...
// ...
ac.logOut();
break;
default:
break;
}
}
}
}
好了,终于不报警告了。在Android中很多的内存泄露都是由于在Activity中使用了非静态内部类导致的,所以当我们使用时要非静态内部类时要格外注意,如果其实例的持有对象的生命周期大于其外部类对象,那么就有可能导致内存泄露。
这篇关于Android中Handler使用不当引起的内存泄露的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!