2017-08-02 52 views
5

为了避免内存泄漏,我编写了以下用于活动并主要用于碎片(使用继承)的方法。该方法应该允许我通过调用弱引用而不是getActivity()(Android避免内存泄漏)?

//this or getActivity() 

方法不会直接引用活动:

private WeakReference<BaseActivity> activityWeakReference = null; 

public BaseActivity getActivityFromWeakReference(){ 
     activityWeakReference = activityWeakReference == null ? 
       new WeakReference<BaseActivity>((BaseActivity)getActivity()) : 
       activityWeakReference; 
     return activityWeakReference.get(); 
    } 

调用此方法getActivityFromWeakReference()而不是getActivity()安全根据内存泄漏的威胁?

如果这样做不安全,我应该退回activityWeakReference并改为调用它的get()方法,以确保安全吗?

我一直在使用它在多个片段,到目前为止我还没有任何问题。我问这个问题,因为我读这个(here):

只要帮手的寿命是 Activity的生命周期内,那么就没有必要使用WeakReference。如果助手 的寿命可能比Activity长,那么当系统 销毁它时,应该使用WeakReference 以避免将Activity保留在对象图中。

到目前为止,我还没有面对一个被引用的元素超出了活动的情况。请大家如果你发现一个错误或可能的只是写在评论中。

+1

请注意,当'activityWeakReference'不为null,但activityWeakReference.get()'为时,您的方法可能会返回null。 –

+0

@Mateus Gondim,感谢您的输入,我在使用之前已经检查过null。 –

回答

5

这是完全可行的。例如,你有这个伪代码:

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     new DownloadTask().execute(); 
    } 

    public void showInfo() { 
    } 

    class DownloadTask extends AsyncTask<Void, Void, Void> { 
     @Override 
     protected Void doInBackground(Void... params) { 
      return null; 
     } 

     @Override 
     protected void onPostExecute(Void data) { 
      // we can call showInfo() activity because Asynctask hold an implicit reference to activity 
      showInfo(); 
     } 
    } 
} 

关于上面的代码,有一种情况会导致内存泄漏。

这里的解释是:

当您创建DownloadTask为例以上,java调用DownloadTaskinner class。内部类将隐含持有对外部类的引用,在这种情况下是MainActivity。而且,当你开始一个asynctask时,这个asynctask将被系统持有,直到它完成。例如,你下载需要30秒。在那30秒内,您旋转您的设备。当你旋转你的设备时,MainActivityre-created,往往旧的活动将被破坏。但在这种情况下,旧活动不会被破坏,因为旧的MainActivity实例由DownloadTask保存,DownloadTask由系统保存。您将泄漏一个活动实例。

为了解决这个,你应该上面的代码更改为:

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     new DownloadTask(this).execute(); 
    } 

    public void showInfo() { 
    } 
} 

class DownloadTask extends AsyncTask<Void, Void, Void> { 
    WeakReference<MainActivity> mainActivityWeakReference; 

    public DownloadTask(MainActivity activity) { 
     mainActivityWeakReference = new WeakReference<MainActivity>(activity); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void data) { 
     if (mainActivityWeakReference.get() != null) { 
      mainActivityWeakReference.get().showInfo(); 
     } 
    } 
} 

在这种情况下,创建新的MainActivity时,旧的没有被DownloadTask(由于弱引用属性)举行,所以未来的旧垃圾将被Android垃圾收集器销毁。您还应该检查每次使用弱引用对象时,因为您不知道GC何时会销毁这些对象。

这是我自己的博客,关于内存泄漏的另一种情况。 Memory leak when using static inner class

希望得到这个帮助。

+0

我应该明白,如果您使用上述方法(getActivityFromWeakReference()),那么您刚才描述的情况就可以了。 –

+2

@MaximeClaude是的,基本上这是真的。你将你的活动的WeakReference保留在“某个地方”,你应该把它作为你的方法来使用(因为在某些情况下,它会是空的,因为GC已经清理了它)。 “某个地方”取决于很多情况,我的例子只是一个。 – hqt

+0

我已经更新了一些代码。希望这个帮助。 – hqt

0

有些情况下,如果你的片段被设置为保留实例,它会比活动时间长,或者你的片段被泄漏。