博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
内存泄露了么: Handlers & Inner Classes
阅读量:6146 次
发布时间:2019-06-21

本文共 4991 字,大约阅读时间需要 16 分钟。

看到一篇关于handler和匿名类关于内存泄露的文章,觉得不错,充分发挥拿来主义,先放这儿看着!

From:http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html

Consider the following code:

public class SampleActivity extends Activity {  private final Handler mLeakyHandler = new Handler() {    @Override    public void handleMessage(Message msg) {      // ...     }  }}

While not readily obvious, this code can cause cause a massive memory leak. Android Lint will give the following warning:

In Android, Handler classes should be static or leaks might occur.

But where exactly is the leak and how might it happen? Let's determine the source of the problem by first documenting what we know:

  1. When an Android application first starts, the framework creates a  object for the application's main thread. ALooper implements a simple message queue, processing  objects in a loop one after another. All major application framework events (such as Activity lifecycle method calls, button clicks, etc.) are contained inside Messageobjects, which are added to the Looper's message queue and are processed one-by-one. The main thread's Looper exists throughout the application's lifecycle.

  2. When a  is instantiated on the main thread, it is associated with the Looper's message queue. Messages posted to the message queue will hold a reference to the Handler so that the framework can call when the Looper eventually processes the message.

  3. In Java, non-static inner and anonymous classes hold an implicit reference to their outer class. Static inner classes, on the other hand, do not.

So where exactly is the memory leak? It's very subtle, but consider the following code as an example:

public class SampleActivity extends Activity {   private final Handler mLeakyHandler = new Handler() {    @Override    public void handleMessage(Message msg) {      // ...    }  }   @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);     // Post a message and delay its execution for 10 minutes.    mLeakyHandler.postDelayed(new Runnable() {      @Override      public void run() { }    }, 60 * 10 * 1000);     // Go back to the previous Activity.    finish();  }}

When the activity is finished, the delayed message will continue to live in the main thread's message queue for 10 minutes before it is processed. The message holds a reference to the activity's Handler, and the Handler holds an implicit reference to its outer class (the SampleActivity, in this case). This reference will persist until the message is processed, thus preventing the activity context from being garbage collected and leaking all of the application's resources. Note that the same is true with the anonymous Runnable class on line 15. Non-static instances of anonymous classes hold an implicit reference to their outer class, so the context will be leaked.

To fix the problem, subclass the Handler in a new file or use a static inner class instead. Static inner classes do not hold an implicit reference to their outer class, so the activity will not be leaked. If you need to invoke the outer activity's methods from within the Handler, have the Handler hold a WeakReference to the activity so you don't accidentally leak a context. To fix the memory leak that occurs when we instantiate the anonymous Runnable class, we make the variable a static field of the class (since static instances of anonymous classes do not hold an implicit reference to their outer class):

public class SampleActivity extends Activity {  /**   * Instances of static inner classes do not hold an implicit   * reference to their outer class.   */  private static class MyHandler extends Handler {    private final WeakReference
mActivity; public MyHandler(SampleActivity activity) { mActivity = new WeakReference
(activity); } @Override public void handleMessage(Message msg) { SampleActivity activity = mActivity.get(); if (activity != null) { // ... } } } private final MyHandler mHandler = new MyHandler(this); /** * Instances of anonymous classes do not hold an implicit * reference to their outer class when they are "static". */ private static final Runnable sRunnable = new Runnable() { @Override public void run() { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mHandler.postDelayed(sRunnable, 60 * 10 * 1000); // Go back to the previous Activity. finish(); }}

The difference between static and non-static inner classes is subtle, but is something every Android developer should understand. What's the bottom line? Avoid using non-static inner classes in an activity if instances of the inner class outlive the activity's lifecycle. Instead, prefer static inner classes and hold a weak reference to the activity inside.

转载于:https://www.cnblogs.com/JavaTechLover/p/3756480.html

你可能感兴趣的文章
Tar打包、压缩与解压缩到指定目录的方法
查看>>
配置spring上下文
查看>>
Python异步IO --- 轻松管理10k+并发连接
查看>>
Oracle中drop user和drop user cascade的区别
查看>>
登记申请汇总
查看>>
Office WORD如何取消开始工作右侧栏
查看>>
Android Jni调用浅述
查看>>
CodeCombat森林关卡Python代码
查看>>
第一个应用程序HelloWorld
查看>>
(二)Spring Boot 起步入门(翻译自Spring Boot官方教程文档)1.5.9.RELEASE
查看>>
Java并发编程73道面试题及答案
查看>>
企业级负载平衡简介(转)
查看>>
ICCV2017 论文浏览记录
查看>>
科技巨头的交通争夺战
查看>>
当中兴安卓手机遇上农行音频通用K宝 -- 卡在“正在通讯”,一直加载中
查看>>
Shell基础之-正则表达式
查看>>
JavaScript异步之Generator、async、await
查看>>
讲讲吸顶效果与react-sticky
查看>>
c++面向对象的一些问题1 0
查看>>
直播视频流技术名词
查看>>