Android Viewpager+Tablayout+Fragment+Webview記憶體優化最終版
阿新 • • 發佈:2021-03-31
如圖:
全域性搜尋首頁是資訊流的形式顯示展示,搜尋頁就是 Viewpager+Tablayout+Fragment,下面說下記憶體優化。
1.Viewpager+Tablayout+Fragment的優化,針對這個我還專門寫了個例子去測試,結果從leakcanary發現切換fragment的時候洩露很嚴重,這是demo裡我之前的寫法,
1.MainActivity.java: package coolpad.testlistfragment; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private TabLayout mTbClassify; private ViewPager mVp; List<Fragment> mFragmentList = new ArrayList<>(); List<String> mTitles = new ArrayList<>(); private TablayoutAdapter tabLayoutAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initId(); initFragments(); initTitles(); initView(); } private void initTitles() { if (mTitles.size() >0 ){ mTitles.clear(); } mTitles.add("1"); mTitles.add("2"); mTitles.add("3"); mTitles.add("4"); mTitles.add("5"); } private void initView() { mTbClassify.addTab(this.mTbClassify.newTab().setText("1"), false); mTbClassify.addTab(this.mTbClassify.newTab().setText("2"), true); mTbClassify.addTab(this.mTbClassify.newTab().setText("3"), false); mTbClassify.addTab(this.mTbClassify.newTab().setText("4"), false); mTbClassify.addTab(this.mTbClassify.newTab().setText("5"), false); tabLayoutAdapter = new TablayoutAdapter(getSupportFragmentManager()); tabLayoutAdapter.setFragments(mFragmentList); tabLayoutAdapter.setTitles(mTitles); mVp.setAdapter(tabLayoutAdapter); mVp.setCurrentItem(1); mVp.setOffscreenPageLimit(1); mTbClassify.setupWithViewPager(mVp); mTbClassify.setTabsFromPagerAdapter(tabLayoutAdapter); } private void initFragments() { FragmentOne fragmentOne = new FragmentOne(); FragmentTwo fragmentTwo = new FragmentTwo(); FragmentThree fragmentThree = new FragmentThree(); FragmentFour fragmentFour = new FragmentFour(); FragmentFive fragmentFive = new FragmentFive(); if (mFragmentList.size() >0){ mFragmentList.clear(); } mFragmentList.add(fragmentOne); mFragmentList.add(fragmentTwo); mFragmentList.add(fragmentThree); mFragmentList.add(fragmentFour); mFragmentList.add(fragmentFive); } private void initId() { mTbClassify = findViewById(R.id.my_tab); mVp = findViewById(R.id.vp_pager); } } 2.TablayoutAdapter.java: package coolpad.testlistfragment; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; public class TablayoutAdapter extends FragmentStatePagerAdapter { List<String> mTitleList = new ArrayList<>(); List<Fragment> mFragmentList = new ArrayList<>(); TabLayout tabLayout; public TablayoutAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mTitleList.size(); } public void setFragments(List<Fragment> fragmentList){ mFragmentList = fragmentList; } public void setTitles(List<String> stringList){ mTitleList = stringList; } @Nullable @Override public CharSequence getPageTitle(int position) { return mTitleList.get(position); } @Override public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { super.destroyItem(container, position, object); } }
這樣的結果是當載入後去切換各個頁面,直接記憶體洩露,比如日誌如下:
coolpad.testlistfragment.FragmentOne instance 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: Leaking: YES (ObjectWatcher was watching this because coolpad.testlistfragment.FragmentOne received 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: Fragment#onDestroy() callback and Fragment#mFragmentManager is null) 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: Retaining 1.2 kB in 36 objects 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: key = df391035-e3e5-4b5d-85da-53050bfe9930 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: watchDurationMillis = 5364 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: retainedDurationMillis = 363 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: key = 075f36bb-0e68-4e22-b2f9-a26dcd5214ac 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: watchDurationMillis = 6920 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: retainedDurationMillis = 1920 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: key = f9464c48-9f3e-4969-a222-fbb1484a7d6f 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: watchDurationMillis = 7355 2021-03-30 17:31:08.523 12950-13056/coolpad.testlistfragment D/LeakCanary: retainedDurationMillis = 2355
這是什麼問題?由於你的fragmentlist一直持有fragment例項物件,導致無法釋放掉fragment造成記憶體洩漏,具體可以參考[https://blog.csdn.net/K_Hello/article/details/82996162],然後又兩個修改方法,方法一:
修改viewpager預設載入的條目為5,那我在載入五個Tab的時候就會一次性載入所有,切換的時候也不會銷燬,也就不會洩露了,但是這種操作會導致fragment裡的webview載入很慢,因為一次性載入五個webview,影響使用者體驗。
方法二:
修改TabAdapter的對fragment的載入方式
package coolpad.testlistfragment; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; public class TablayoutAdapter extends FragmentStatePagerAdapter { List<String> mTitleList = new ArrayList<>(); // List<Fragment> mFragmentList = new ArrayList<>(); public TablayoutAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { if (position == 0){ return new FragmentOne(); }else if (position == 1){ return new FragmentTwo(); }else if (position == 2){ return new FragmentThree(); }else if (position == 3){ return new FragmentFour(); }else if (position == 4){ return new FragmentFive(); } } @Override public int getCount() { return mTitleList.size(); } // public void setFragments(List<Fragment> fragmentList){ // mFragmentList = fragmentList; // } public void setTitles(List<String> stringList){ mTitleList = stringList; } @Nullable @Override public CharSequence getPageTitle(int position) { return mTitleList.get(position); } @Override public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { super.destroyItem(container, position, object); } }
getItem的時候直接new出來,這種修改也不會記憶體洩漏。
2.Webview的優化
見我之前寫的新增連結描述
在執行完這兩種操作後就不會記憶體洩露了。