------ 「ViewPage2 オフスクリーン読み込み」
序文
ここでは ViewPage については話しません。古いものではなく新しいものを購入し、古いものではなく新しいものを使用してください。
ただし、ViewPage と ViewPage2 を比較してください。
ViewPage2 は RecyclerView に基づいて処理されます。そのため、RecyclerView のキャッシュとプリロードのメカニズムも継承しました。
オフスクリーンロードのメカニズムを明確に確認するには、まずプリロードをオフにします。
((RecyclerView)viewPager.getChildAt(0)).getLayoutManager().setItemPrefetchEnabled(false);
オフスクリーンロードとは何ですか
オフスクリーン読み込みの最も重要な制御パラメータ: OffscreenPageLimit
この値は、スライド ビューで現在表示されているページ以外の方向に保持する必要があるページの数を表します。
たとえば、水平ページングを使用する場合、この値は左側と右側に保持するページ数を表します。
また、垂直ページネーションを使用する場合、この値は上下に確保するページ数を表します。
ページを予約する方法は、追加のレイアウト スペースを拡張することで実現されます。LinearLayoutManager を例に取ると、最も重要な手順は、calculateExtraLayoutSpace メソッドを書き直すことです。
/**
* 计算额外的布局空间
*/
@Override
protected void calculateExtraLayoutSpace(@NonNull RecyclerView.State state,
@NonNull int[] extraLayoutSpace) {
int pageLimit = getOffscreenPageLimit();
if (pageLimit == OFFSCREEN_PAGE_LIMIT_DEFAULT) {
// 仅在需要时才对屏幕外页面进行自定义预取
super.calculateExtraLayoutSpace(state, extraLayoutSpace);
return;
}
// 计算多pageLimit*2个页面大小的空间
final int offscreenSpace = getPageSize() * pageLimit;
extraLayoutSpace[0] = offscreenSpace;
extraLayoutSpace[1] = offscreenSpace;
}
/**
* 获取单个页面大小
*/
int getPageSize() {
final RecyclerView rv = mRecyclerView;
// 水平分页时,取去除了左右内边距后的RecyclerView宽度
// 垂直分页时,取去除了上下内边距后的RecyclerView高度
return getOrientation() == ORIENTATION_HORIZONTAL
? rv.getWidth() - rv.getPaddingLeft() - rv.getPaddingRight()
: rv.getHeight() - rv.getPaddingTop() - rv.getPaddingBottom();
}
このメソッドは、LinearLayoutManager がレイアウトする必要がある追加スペースの量をピクセル単位で計算します。デフォルトのレイアウト スペースが 1 ページのサイズであることがわかっているため、追加のレイアウト スペースは OffscreenPageLimit*2 の 1 ページ サイズである必要があり、計算結果は int 配列タイプの extraLayoutSpace 構造体に格納されます。
- extraLayoutSpace[0] は上部または左側の追加スペースに適用されます。
- extraLayoutSpace[1] は、下部または右側の追加スペースに適用されます。
この追加作成されたページは現在の画面には表示されませんが、実際にはビュー階層に追加されています。そうすることで、ページを切り替えるときのビューの作成とレイアウトにかかる時間が短縮され、スライド時の ViewPager2 の全体的な流暢性が向上します。
前の 2 つの記事を組み合わせると、キャッシュ多重化メカニズムからプリフェッチ メカニズム、現在のオフスクリーン ロード メカニズムに至るまで、RecyclerView と ViewPager2 がスライドのスムーズさを向上させるために多大な努力を払ってきたことがわかります。
違いは次のとおりです。
- キャッシュ再利用メカニズムは、作成されたページをキャッシュして、新規入力画面のページを再利用することによって実装されます。
- プリフェッチの仕組みは、UI スレッドのアイドル時間を利用して、次に画面に入力するページを事前に作成してキャッシュすることで実現されます。
- オフスクリーン読み込みメカニズムは、追加のレイアウト スペースを拡張して、画面の両側にページを事前に作成および予約することによって実装されます。
呼び出しメソッド フローの観点から見ると、従来の onCreateViewHolder メソッドと onBindViewHolder メソッドに加えて、オフスクリーン ロード メカニズムは複数の onViewAttachedToWindow メソッドも実行して、ページをビュー階層に事前に追加します。
オフスクリーンページ制限
ViewPager が常に人々から批判されてきた点の 1 つは、ViewPager によって設定される OffscreenPageLimit のデフォルト値が 1 であり、1 より小さい外部変更値を許可しないことです。つまり、「オフスクリーン読み込みを強制的に開く」ということです。仕組み」。
これは、ViewPager で構築されたスライディング ビューでは、開発者が必要かどうかに関係なく、少なくとも 1 ~ 2 ページが画面外に読み込まれることを意味し、これにより、Fragment のライフ サイクルに依存する一連のロジックが発生します。異常に実行され、予期しない結果が生じる場合、開発者は遅延読み込みメカニズムを手動で実装する必要があります。
対照的に、ViewPager2 によって設定される OffscreenPageLimit のデフォルト値は -1 です。つまり、「オフスクリーン読み込みメカニズムはデフォルトでは有効になっていません。」
この場合、RecyclerView のキャッシュ多重化メカニズムとプリフェッチメカニズムのみが機能します。 。
public static final int OFFSCREEN_PAGE_LIMIT_DEFAULT = -1;
また、外部からインポートされる変更値は 1 より大きい整数にすることができます。
public void setOffscreenPageLimit(@OffscreenPageLimit int limit) {
if (limit < 1 && limit != OFFSCREEN_PAGE_LIMIT_DEFAULT) {
throw new IllegalArgumentException(
"Offscreen page limit must be OFFSCREEN_PAGE_LIMIT_DEFAULT or a number > 0");
}
mOffscreenPageLimit = limit;
// Trigger layout so prefetch happens through getExtraLayoutSize()
mRecyclerView.requestLayout();
}
さらに、ViewPager2 は RecyclerView に基づいて構築されています。したがって、オフスクリーン読み込みメカニズムがデフォルトで有効になっていない場合でも、プリフェッチ メカニズムは正常に動作します。
しかし実際には、ほとんどの開発者は便宜上、つまりすべてのページをキャッシュするために、この値を「総ページ数 - 1」に設定することがよくあります。しかし、これは標準化されていません。
OffscreenPageLimit のパフォーマンスを設定する
OffscreenPageLimit 値は 1 です
OffscreenPageLimit 値が 1 の場合、つまり、1 ページが左側と右側のオフスクリーンにロードされます。
1. スライディング ビューが初期化されると、左側にはページ アイテムがなくなるため、position=0 と Position=1 のページ アイテムのみが現在のビュー階層に追加されます。
2. 画面を左にスライドすると、position=2 のページ項目が現在のビュー階層に追加されますが、position=0 のページ項目は現在のビュー階層に残り、プリフェッチ メカニズムがWorkを起動し、あらかじめposition=3のページアイテムを作成し、mCachedViewに入れておきます。
3. 画面を再度左にスワイプすると、スライディング ビューによって、事前にフェッチされた Position=3 のページ項目が取り出され、現在のビュー階層に追加されます。一方、position=1 のページ項目は引き続きビュー階層に残ります。現在のビュー階層を設定し、position=4 でページ項目のプリフェッチを有効にします。
4. 同時に、position=0 のページ項目も左にスライドするジェスチャで画面の外に移動され、mCachedView に配置されます。 5. 画面を 3 回目で左にスワイプすると
、プリフェッチされた位置 = 4 も取り出されます。 ページ アイテムを現在のビュー階層に追加し、ページ アイテムを現在のビュー階層の位置 = 2 に保持し、ページ アイテムの位置 = 5 のプリフェッチを有効にします。
6. この時点では、mCachedView のサイズ制限を超えていないため、画面から削除された次の Position=1 のページ項目も mCachedView に配置されます。
7. 4 回目に画面を左にスワイプすると、同様に、position=5 のプリフェッチされたページ項目が取り出されて現在のビュー階層に追加され、position=3 のページ項目はビュー階層に保持されます。現在のビュー階層。position=6 のページ項目のプリフェッチ。
8. ただし、mCachedView のサイズ制限を超えているため、画面から削除された、position=2 の次のページ項目に入ろうとすると、まず、position=0 のページ項目が最初の順序で mCachedView から削除されます。 -in-first-out を実行し、RecyclerPool の itemType に対応する ArrayList コンテナに入れます。
OffscreenPageLimit 値は 3 です
OffscreenPageLimit 値が 3 の場合、つまり、3 ページが画面の左側と右側にオフにロードされます。
1. スライディング ビューが初期化されると、左側にはページ アイテムがなくなるため、position=0 から Position=3 までのページ アイテムのみが現在のビュー階層に追加されます。
2. 画面を左にスライドすると、position=4 のページ項目が現在のビュー階層に追加されますが、position=0 のページ項目は現在のビュー階層に残り、プリフェッチ メカニズムがWorkを起動し、あらかじめposition=5のページアイテムを作成し、mCachedViewに入れておきます。
3. 画面を再度左にスワイプすると、スライド ビューにより、事前にフェッチされたposition=5 のページ項目が取得され、現在のビュー階層に追加されます。一方、position=1 のページ項目は引き続きビュー階層に残ります。現在のビュー階層を設定し、position=6 でページ項目のプリフェッチを有効にします。
すべてのページをキャッシュするには、OffscreenPageLimit をページの総数 - 1 に設定します。
適切な OffscreenPageLimit 値はどれですか?
OffscreenPageLimit 値の設定が大きすぎると、特に一部のローエンド モデルで、アプリケーションに比較的大きなメモリ負荷がかかります。
ただし、OffscreenPageLimit 値の設定が 1 など小さすぎる場合、オフスクリーン読み込みメカニズムを利用してページ スライドのスムーズさを向上させることができません。
一般的に、3 ~ 4 個のページ アイテムを同時にアクティブにしておく方が適切な値です。これにより、ユーザーがページを前後にめくる際の流暢性が向上する一方で、パフォーマンスは向上しません。アプリケーションに対するメモリが多すぎるため、圧力がかかります。もちろん、フラグメント再構築の処理ロジックを維持し、リサイクル/再利用を考慮する必要もあります。
最良の場合でも、動作パフォーマンスとパフォーマンスへの影響のバランスをとるために、アプリケーションの現在のメモリ使用量に応じてこの値を動的に調整できることが望まれます。
要約する
さて、以上が ViewPager2 のオフスクリーン読み込みメカニズムの全内容ですが、いつものように前回の記事の内容を要約しましょう。
オフスクリーンロードメカニズム | |
---|---|
目的 | ページを切り替えるときのビューの作成とレイアウトにかかる時間を短縮し、それによってスライド時の ViewPager2 の全体的な流暢性が向上します。 |
道 | 画面の両側にページを事前に作成・予約することで、追加のレイアウトスペースを拡張できます。 |
キーパラメータ | mOffscreenPageLimit、デフォルト値は -1 です。つまり、オフスクリーン読み込みメカニズムはデフォルトでは有効になっていません。 |
パフォーマンスへの影響 | ホワイトスクリーン時間、流暢さ、メモリ使用量など。 |
TabLayoutあり | 1. デフォルトでは、スライド方向にさらに 1 ページが画面からロードされます; 2. ターゲットからの距離が遠すぎる場合、最初にプレジャンプし、次にロングジャンプします。 |
ご提案ポイント | 1. アプリケーションの現在のメモリ使用量に応じて、mOffscreenPageLimit の値を動的に調整して、動作とパフォーマンスへの影響のバランスをとります。2. フラグメント再構築の処理ロジックを維持し、リサイクル/再利用を考慮する必要があります。 |