1. 程式人生 > 其它 >Android Viewpager+Tablayout+Fragment+Webview記憶體優化最終版

Android Viewpager+Tablayout+Fragment+Webview記憶體優化最終版

如圖:
在這裡插入圖片描述在這裡插入圖片描述

全域性搜尋首頁是資訊流的形式顯示展示,搜尋頁就是 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的優化
見我之前寫的新增連結描述

在執行完這兩種操作後就不會記憶體洩露了。