美文网首页Android 开发相关文章收集
Android内存泄露常见场景及规范

Android内存泄露常见场景及规范

作者: 董成鹏 | 来源:发表于2018-11-30 16:16 被阅读0次
  1. AsyncTask造成的泄露
    规范:所有AsyncTask必须是静态的或者单独的类, 绝对不允许非静态内部AsyncTask.
    如果AsyncTask需要访问外部的Activity或者Module, 在构造函数中传入这些参数, 然后使用WeakReference包装。

  2. Handler, Runnable造成的泄露
    规范:在Activity onDestroy中, 必须调用handler.removeCallbacksAndMessages(null)
    对于AlertDialog, 其Listener必须使用DetachableClickListener包装

public final class DetachableClickListener implements DialogInterface.OnClickListener {

  public static DetachableClickListener wrap(DialogInterface.OnClickListener delegate) {
    return new DetachableClickListener(delegate);
  }

  private DialogInterface.OnClickListener delegateOrNull;

  private DetachableClickListener(DialogInterface.OnClickListener delegate) {
    this.delegateOrNull = delegate;
  }

  @Override public void onClick(DialogInterface dialog, int which) {
    if (delegateOrNull != null) {
      delegateOrNull.onClick(dialog, which);
    }
  }

  public void clearOnDetach(Dialog dialog) {
    dialog.getWindow()
        .getDecorView()
        .getViewTreeObserver()
        .addOnWindowAttachListener(new OnWindowAttachListener() {
          @Override public void onWindowAttached() { }
          @Override public void onWindowDetached() {
            delegateOrNull = null;
          }
        });
  }
}

DetachableClickListener clickListener = wrap(new DialogInterface.OnClickListener() {
  @Override public void onClick(DialogInterface dialog, int which) {
    MyActivity.this.makeCroissants();
  }
});

//然后在使用的时候
AlertDialog dialog = new AlertDialog.Builder(this) //
    .setPositiveButton("Baguette", clickListener) //
    .create();
clickListener.clearOnDetach(dialog);
dialog.show();
  1. HandlerThread造成的泄露
    规范:可以有一个全局的BackgroudThread不退出。
    其余的HandlerThread在Activity销毁的时候必须调用quit或者quitSafely方法

  2. 单例持有Context
    规范:单例如果要持有Context, 必须只能持有ApplicationContext.

  3. Bitmap使用不当
    规范:Bitmap使用完必须调用recycle, 并且手动置空

  4. View绘制不当
    规范:由于View绘制的时候会频繁调用onDraw, 所以在onDraw中不能去生成Rect,RectF,Paint等实例。

  5. 共轭方法必须成对出现
    比如在onResume中register,必须在onPause中unRegister

  6. 所有Closeable对象必须close
    包括但不局限于:File, InputStream, OutputStream等。

  7. 不要跨线程置空
    赋值在A线程, 则置空也必须在A线程。 除非我们有十二分的理由说不能在A线程置空。

  8. RxJava使用不当
    规范1:所有Subscription或者Disposable必须clear或者dispose
    规范2:线程切换如果用到了Looper,必须在所有使用了非静态内部类的操作符之上使用onTerminateDetach操作符

  9. WebView造成的内存泄露
    规范1:WebView必须动态添加, 不要静态添加
    规范2:WebView最好使用单独进程
    规范2:WebView销毁必须按照如下格式

//先让webviewJ下载空内容
mWebView.loadDataWithBaseURL(null,"","text/html","utf-8",null);
//然后把webview从viewTree中移除
if(mWebView != null){
  ViewGroup parent = (ViewGroup)mWebView.getParent();
  if(parent != null){
    parent.removeView(mWebView);
  }
} 
 mWebView.stopLoading(); 
// 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错 mWebView.getSettings().setJavaScriptEnabled(false); mWebView.clearHistory(); 
mWebView.clearView();

//移除webview中所有的view
 mWebView.remvoeAllViews();
//销毁webview
mWebView.destroy();
mWebView = null;
  1. 严禁static的View和Drawable.

  2. 不要依赖finalize方法进行清理,finalize是救命稻草,但不一定能救命
    finalize方法去执行清理,JVM只保证finalize方法最多被执行一次, 也就是说finalize方法可能一次都不会被执行。
    JVM会把实现了finalize方法的对象包装成FinalizerReference, 然后放到一个双向队列中, 当gc线程工作工作的时候,不断取出该队列的元素, 然后执行finalize方法, 也就是说finalize方法不是在主线程中执行的。

  3. 创建的时候先创建父类, 销毁的时候先销毁自己。
    也就是说在onCreate中先调用super.onCreate(), 然后在做自己的事情
    在onDestroy的时候, 先销毁自己持有的引用, 然后在super.onDestroy()

  4. 在onDestroy中销毁属性动画(理论上应该销毁一切动画)

  5. 尽量不要在非静态内部类中持有外部类的属性,因为在非静态内部类中, 会把所有用到的外部类的属性作为自己的属性给保存起来, 一般情况下这没有什么问题, 但是一旦非静态内部类存活时间比外部类存活时间长, 就容易出现问题

相关文章

网友评论

    本文标题:Android内存泄露常见场景及规范

    本文链接:https://www.haomeiwen.com/subject/itlhcqtx.html