参考网上别人的文章,做一下内存泄漏情况的总结及解决方法
如果单例的成员中有Context的话,由于单例在生成后就一直存在于内存中,所以其持有的Context对象不会被回收,即Activity很难会被回收。
可以让其持有Application的Context对象即可:
public class SingleInstanceTest {
private static SingleInstanceTest sInstance;
private Context mContext;
private SingleInstanceTest(Context context){
this.mContext = context.getApplicationContext();
}
public static SingleInstanceTest newInstance(Context context){
if(sInstance == null){
sInstance = new SingleInstanceTest(context);
}
return sInstance;
}
}
另外,当某些类需要持有Context时,也可能会出现和上述类似的情况,这时可以使用弱引用来规避这一情况:
public class Sample {
private WeakReference<Context> mWeakReference;
public Sample(Context context){
this.mWeakReference = new WeakReference<>(context);
}
public Context getContext() {
if(mWeakReference.get() != null){
return mWeakReference.get();
}
return null;
}
}
当Activity中有非静态内部类或者匿名类的对象时,这些对象会持有该Activity对象的引用,如果内部对象的存活时间很长,会导致Activity无法被回收。
解决方法是将其以静态内部类的形式重写或者使用弱引用。
适用于Thread Handler AsyncTask等耗时工具
使用静态内部类:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MyAscnyTask().execute();
}
static class MyAscnyTask extends AsyncTask<Void, Integer, String>{
@Override
protected String doInBackground(Void... params) {
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "";
}
}
}
handler引起的内存泄漏:
第一种解决方法 使用静态内部类以及弱引用
//自定义handler
public static class HandlerHolder extends Handler {
WeakReference<OnReceiveMessageListener> mListenerWeakReference;
/**
* @param listener 收到消息回调接口
*/
HandlerHolder(OnReceiveMessageListener listener) {
mListenerWeakReference = new WeakReference<>(listener);
}
@Override
public void handleMessage(Message msg) {
if (mListenerWeakReference!=null && mListenerWeakReference.get()!=null){
mListenerWeakReference.get().handlerMessage(msg);
}
}
}
//创建handler对象
private HandlerHolder handler = new HandlerHolder(new OnReceiveMessageListener() {
@Override
public void handlerMessage(Message msg) {
switch (msg.what){
case 1:
TextView textView1 = (TextView) msg.obj;
showBottomInAnimation(textView1);
break;
case 2:
TextView textView2 = (TextView) msg.obj;
showBottomOutAnimation(textView2);
break;
}
}
});
//发送消息
Message message = new Message();
message.what = 1;
message.obj = textView;
handler.sendMessageDelayed(message,time);
第二种解决方法:移除消息队列中所有的消息
@Override
protected void onDestroy() {
super.onDestroy();
if(handler!=null){
handler.removeCallbacksAndMessages(null);
handler = null;
}
}
private static TestResource mResource = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(mResource == null){
mResource = new TestResource();
}
}
class TestResource {
//里面代码引用上下文,Activity.this会导致内存泄漏
}
BroadcastReceiver,ContentObserver,FileObserver,Cursor,Callback等在 Activity onDestroy 或者某类生命周期结束之后一定要 unregister 或者 close 掉否则这个 Activity 类会被 system 强引用,不会被内存回收。值得注意的是,关闭的语句必须在finally中进行关闭,否则有可能因为异常未关闭资源,致使activity泄漏
这样就在Activity内部创建了一个非静态内部类的单例,每次启动Activity时都会使用该单例的数据,这样虽然避免了资源的重复创建,不过这种写法却会造成内存泄漏,因为非静态内部类默认会持有外部类的引用,而该非静态内部类又创建了一个静态的实例,该实例的生命周期和应用的一样长,这就导致了该静态实例一直会持有该Activity的引用,导致Activity的内存资源不能正常回收。
参考:
https://github.com/yangchong211/YCBlogs/blob/master/android/优化相关/01.内存泄漏优化.md
https://www.jianshu.com/p/65f914e6a2f8