Weak reference instead of getActivity() (Android avoid memory leak)?

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-03 13:32:17

It is totally feasible. For example you have this pseudocode code:

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();
        }
    }
}

On above code, there is a situation will caused memory leak.

Here is the explanation:

When you create DownloadTask as above example, java call DownloadTask is an inner class. An inner class will implicit holds a reference to outer class, in this case is MainActivity. Moreover, when you start an asynctask, that asynctask will be held by system until it finish. For example, you download takes 30 seconds. In that 30 seconds, you rotate your device. When you rotate your device, MainActivity is re-created and often old activity will be destroyed. But in this case old activity isn't destroyed because the old MainActivity instance is held by DownloadTask and DownloadTask is hold by system. You will leak one activity instance.

For fixing this, you should change above code to:

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();
        }
    }
}

In this case, when new MainActivity is created, the old one isn't held by DownloadTask (due to weak reference attribute), so the old one will be destroyed by Android Garbage Collector in future. You also should to check every time you use a weak reference object, because you don't know exactly when GC will destroyed those object.

Here is my own blog about another situation of memory leak. Memory leak when using static inner class

Hope this help.

There are some case, if your fragment is set to retain instance, it'll be longer than activity, or if your fragment is leaked.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!