使用FragmentStatePagerAdapter時發現的內存泄露問題


這篇文章想說的並非是由於使用 FragmentStatePagerAdapter 而導致的內存泄漏,內存泄漏的真正原因和 FragmentStaePagerAdapter 並無直接關聯,但是使用 FragemntStatePagerAdapter 能讓你更加直觀的發現內存泄漏。

 

      我先說說我之前遇到的問題。我們都知道,當使用 FragmentSataePagerAdapter 的時候,超出緩存范圍的 Fragment 會被 FragmentManager 給 remove 掉,也就是會被銷毀實例,所以FragmentSatatePagerAdapter 很適合用來處理多 Fragment 頁面的狀況。但我遇到的情況是,當我的 Fragment 超出緩存范圍時,確實被銷毀了,但是它所持有的內存卻並未得到釋放,也就是說它內部的數據等等並未銷毀和回收。如果是頁面很多的情況下,很容易就會造成程序的卡頓甚至 OOM。

    一般來說,造成內存泄漏的最大可能就是某處持有該對象的引用,導致該對象無法釋放內存。經排查,我在使用 ViewPager 時,創建了一個 Fragment 的 List ,用來管理所有要添加到 ViewPager 中的 Fragment ,這里的 List 可能強引用了所有的Fragment,所以造成了內存泄漏 。代碼如下:

private List<Fragment> fragmentList = new ArrayList<>();  //創建List,用來管理所有要添加到ViewPager的Fragment

//添加Fragment private void setUpFragments() { fragmentList.clear(); fragmentList.add(new SampleListFragment()); fragmentList.add(new SamplePagerFragment()); fragmentList.add(new BlankFragment()); } viewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) { @Override public Fragment getItem(int position) { return fragmentList.get(position); //從Fragment隊列中得到Fragment並加入到ViewPager中 } @Override public int getCount() { return fragmentNames.size(); } });

 

    那么如何來驗證是不是這里的原因造成內存泄漏呢?想要證明,首先就不能夠在使用 List 來管理 Fragment對象了。ViewPager最麻煩的是你不能自己使用 FragmentManager 的transaction 來添加 Fragment ,因為這些操作是在 ViewPager 的內部去完成的。最后我考慮使用 List 來管理Fragment的CLASS 類,然后再通過反射的方式,創建出 Fragment 對象。這樣 Fragment 對象就不會被 List 持有引用了。具體代碼如下:

private List<Class> fragmentNames;   //創建List來管理 Fragment的 Class


//添加Fragment的Class到List中
private void setUpFragments() {
if(fragmentNames == null){ fragmentNames = new ArrayList<>(); } fragmentNames.clear(); fragmentNames.add(SampleListFragment.class); fragmentNames.add(SampleListFragment.class); fragmentNames.add(SampleListFragment.class); fragmentNames.add(SampleListFragment.class);
} viewPager.setAdapter(
new FragmentStatePagerAdapter(getSupportFragmentManager()) { @Override public Fragment getItem(int position) { try { return (Fragment) fragmentNames.get(position).newInstance(); //反射加載Fragment } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } @Override public int getCount() { return fragmentNames.size(); } });

如果不會反射的同學可以看一下我前面寫的介紹反射的簡單使用的文章。

 

現在再來檢查程序的內存狀況,你就會發現內存能夠正確的被釋放,內存泄漏的問題也就解決了。

其實我以前使用 ViewPager + Fragment 的時候也並沒有注意到內存泄漏的問題,直到使用了FragmentStatePagerAdapter 時才發現原來的寫法可能會造成內存泄漏。當然,程序中還會有很多地方稍不注意就會導致內存泄漏的問題,我們平時寫代碼時應該多多考慮內存泄漏的問題,並對此進行優化。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM