Android パフォーマンスの最適化 - ViewPager + フラグメント キャッシュの最適化

タイトルを見ると、ViewPager が何なのか少し混乱するかもしれません。昔は ViewPager を使用していましたが、現在では ViewPager2 が使用されることが多くなっているため、ViewPager (ViewPager, ViewPager2) がこの 2 つの代わりに使用されています。主なことは、この 2 つの違いを紹介することです。

ViewPagers のネストされたフラグメント アーキテクチャは、Douyin のホームページ、主要な電子商取引アプリ (淘宝網、JD.com、Pinduoduo) のホームページなど、一般的に使用されるアプリのあらゆる場所で見ることができます。 左または右にスライドしてタブを切り替えることができます。 ; ただし、 ViewPager のプリロード メカニズムのため、最初に ViewPager のソース コードを見てみましょう。

public void setOffscreenPageLimit(int limit) {
   
    
    
    if (limit < DEFAULT_OFFSCREEN_PAGES) {
   
    
    
        Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "
                + DEFAULT_OFFSCREEN_PAGES);
        limit = DEFAULT_OFFSCREEN_PAGES;
    }
    if (limit != mOffscreenPageLimit) {
   
    
    
        mOffscreenPageLimit = limit;
        populate();
    }
}

offscreenPageLimit (オフスクリーン読み込み) の値を設定すると、limit の値は制限されており、DEFAULT_OFFSCREEN_PAGES より小さくすることはできないことがわかります。

private static final int DEFAULT_OFFSCREEN_PAGES = 1;

これは、ViewPager がデフォルトでプリロードをサポートしていることを意味します。下の図を見てみましょう。

ここに画像の説明を挿入します

Android パフォーマンス最適化ファイルのフルバージョンが必要な場合は、クリックして無料で入手してください

赤い領域がデフォルトのホームページである場合、ViewPager のデフォルトのプリロードしきい値に従って、左側と右側のページもロードされます。ネットワーク リクエストがある場合、つまり左側のページを開いていない場合、デフォルトですでにネットワーク要求が行われていますが、トラフィックを密かに消費するため、エクスペリエンスは非常に悪いです。

理想的には、ページを開いたときにページを読み込む必要があるため、遅延読み込みを通じてページを最適化する必要があります。

1 ViewPager の遅延読み込みの最適化

1.1 ViewPager のキャッシュ メカニズム

Fragment を使用すると、開いたページが再構築されず、更新されずに戻ってくることがよくあります。Fragment がキャッシュされていると考えている人が多いです。実際には、Fragment にキャッシュがあるのではなく、ViewPager にキャッシュ機能があるのです。 ;

単一のアクティビティ + 複数のフラグメント アーキテクチャを使用した友人がいる場合は、開いたページが再び返されるとフラグメントが再構築されるため、どちらのアーキテクチャにも長所と短所があることがわかります。鍵は、どのように選択するかによって異なります。 ViewPager のキャッシュ メカニズムについては以下をご覧ください。

public void setAdapter(@Nullable PagerAdapter adapter) {
   
    
    
    if (mAdapter != null) {
   
    
    
        ①
        mAdapter.setViewPagerObserver(null);
        mAdapter.startUpdate(this);
        for (int i = 0; i < mItems.size(); i++) {
   
    
    
            final ItemInfo ii = mItems.get(i);
            mAdapter.destroyItem(this, ii.position, ii.object);
        }
        mAdapter.finishUpdate(this);
        mItems.clear();
        removeNonDecorViews();
        mCurItem = 0;
        scrollTo(0, 0);
    }final PagerAdapter oldAdapter = mAdapter;
    mAdapter = adapter;
    mExpectedAdapterCount = 0;if (mAdapter != null) {
   
    
    
        if (mObserver == null) {
   
    
    
            mObserver = new PagerObserver();
        }
        mAdapter.setViewPagerObserver(mObserver);
        mPopulatePending = false;
        final boolean wasFirstLayout = mFirstLayout;
        mFirstLayout = true;
        mExpectedAdapterCount = mAdapter.getCount();
        if (mRestoredCurItem >= 0) {
   
    
    
            mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
            setCurrentItemInternal(mRestoredCurItem, false, true);
            mRestoredCurItem = -1;
            mRestoredAdapterState = null;
            mRestoredClassLoader = null;
        } else if (!wasFirstLayout) {
   
    
    populate();
        } else {
   
    
    requestLayout();
        }
    }

    // Dispatch the change to any listeners
    if (mAdapterChangeListeners != null && !mAdapterChangeListeners.isEmpty()) {
   
    
    
        for (int i = 0, count = mAdapterChangeListeners.size(); i < count; i++) {
   
    
    
            mAdapterChangeListeners.get(i).onAdapterChanged(this, oldAdapter, adapter);
        }
    }
}

中心となるメソッドは setAdapter です。RecyclerViewと同様にキャッシュがあるので、ページがスライドするときに、キャッシュにページが存在していればキャッシュから取得します。そうでない場合は、新しいページを作成する必要があるので、やってみましょうPagerAdapter に注意してください

public abstract class PagerAdapter {
   
    
    
    private final DataSetObservable mObservable = new DataSetObservable();
    private DataSetObserver mViewPagerObserver;

    public static final int POSITION_UNCHANGED = -1;
    public static final int POSITION_NONE = -2;

    public abstract int getCount();
    //开始更新
    public void startUpdate(@NonNull ViewGroup container) {
   
    
    
        startUpdate((View) container);
    }
    //初始化页面
    @NonNull
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
   
    
    
        return instantiateItem((View) container, position);
    }
    //销毁页面
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
   
    
    
        destroyItem((View) container, position, object);
    }
    //结束刷新
    public void finishUpdate(@NonNull ViewGroup container) {
   
    
    
        finishUpdate((View) container);
    }
}

PagerAdapter は抽象クラスであるため、これらのメソッドは特定の実装クラスによって実装する必要があります。ViewPager を使用して Fragments をネストする場合は、FragmentPageAdapter を使用します。

その後、setAdapter メソッドに戻ります

①: グローバル変数 mAdapter があり、それが最初にロードされると、mAdapter は空になります。

②: ここで、渡したアダプターを mAdapter に割り当てます。

③: この時点では、mAdapter は空ではありませんが、注意が必要なパラメータがいくつかあります。

wasFirstLayout = true
mRestoredCurItem = -1

⑤に直接進み、onMeasureを実行するrequestLayoutメソッドを呼び出し、このメソッド内でpopulateメソッドが実行されます(階段は自分で登ることができます)

ポピュレートは何をしましたか? コードが多すぎるのでここには投稿しません。画像を参照してください。

ここに画像の説明を挿入します

デフォルトのキャッシュ (mOffscreenPageLimit = 1) の場合、3 つのフラグメントが mItems にキャッシュされます。

private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();

ページがスライドすると、page2 が現在のページになります。では、ViewPager のデータ入力は何を行うのでしょうか?

おすすめ

転載: blog.csdn.net/m0_70748458/article/details/130384728