最近、Flutterでの関連するパフォーマンスの最適化により、多くのパフォーマンスデータを収集した後、ListViewコンポーネントが一部のシナリオ(追加の読み込みなど)でページジャムを引き起こす可能性があることがわかりました。 XianyuのFlutterの機能的なフルシーン。コンテナを回転させます。ただし、このコンポーネントはオープンソースではないため、記事に記載されているアイデアから高性能のListViewを研究開発してみます。このシリーズは4〜5の記事に分割される予定で、最初の2つは主に既存の問題を調査および分析し、最後の3つは実際に開発されています。
原則:
1.ウィジェット、要素、およびレンダリングツリーはどのように形成されますか?
2.ListViewの構築プロセスとパフォーマンスの問題の分析
実用的な記事:
1. Flutterは、高性能で多機能のListViewコンポーネントをどのように設計しますか
2.ListViewのパフォーマンスの問題と最適化ソリューション
3.オープンソース!!!!
ps:コンポーネントは基本的に基本的な機能とパフォーマンスの最適化を完了しており、まもなくオープンソースになります。賞賛に注意し、最新情報をお見逃しなく!!
前号では、ListViewコンポーネントの機能設計を分析しました。この号では、パフォーマンスの方向にとどまっているListViewの根本原因と最適化スキームの分析に焦点を当てました。
1. ListViewにパフォーマンスの問題がありますか?
日常のビジネス開発では、さまざまなシナリオでListViewコンポーネントを使用します。これを使用して、リストページをすばやく完成させたり、一部の小さな画面デバイスに適応させたりします。では、ネイティブのListViewコンポーネントを使用すると、パフォーマンスの問題が発生しますか?答えは「はい」です。実際のビジネスシナリオでは、このようなページに遭遇しました(UIはこのようには見えません)
これは垂直リストであり、各行の項目は3つのTextFieldです。写真に示すように、通常、パフォーマンスオーバーレイが表示されます。プロファイルモードでは、このページはVivo X23(Snapdragon 660)で大幅に遅れています。
2.なぜ遅れがあるのですか?
ファンダメンタル
リストをスライドさせるプロセスは、実際には1つの画像で構成されていることがわかっています。この用語は、フレームと呼ばれます。ほとんどの人にとって、1秒あたりの画像が60に達すると(一般に60FPSとして知られています)、プロセス全体がスムーズになります。60FPS未満の場合、動かなくなったように感じます。
[画像のアップロードに失敗しました...(image-7b2aef-1616072584879)]
60フレーム/秒は、2つのフレーム間の平均間隔が16.7msであることを意味します。16.7msを超えると、知覚が途切れます。システムが提供するDevTooolsツールを使用すると、上記の例では、フレームがフリーズするまでに最大130ミリ秒かかることがわかります。
フレームを描画するために、システムはどの段階を経る必要がありますか?
1つのフレームに16.7ms以上かかるのはなぜですか?この問題を明確にするために、フレームを描画するためにFlutterが何をするのかを知る必要があります。
実際、 答えを得るには、FlutterプロジェクトでdrawFrame()を検索するだけで済みます。
この方法についての英語のコメントは非常に詳細であり、皆さんにチェックすることをお勧めします。全部で10のステップがあり、その中で開発者に密接に関連する次のステップがあります。
アニメーション->ビルド->レイアウト->描画->構成
ラグの原因
DevToolsの分析チャートと組み合わせると、を見ることができます。上記の130msの主な時間のかかる構築は、レイアウトで呼び出されるビルドメソッドに集中しています。
上記のフレーム描画プロセスによると、レイアウトがビルドされた後、なぜレイアウトに再度ビルドがあるのかがわかります。
ListViewの各アイテムについて、ビルドフェーズですべてのアイテムがビルドされるわけではありません。しかし、レイアウト段階では、画面の現在のサイズとバッファ領域のスコープに応じて、各アイテムが動的に構築されます。プロセスは図に示されています(upYangからの写真)
したがって、上記の分析図では、レイアウトは主にレイアウトのListViewであり、その中のビルドは各子ノードです。実際、注意深く見てください。各ビルドの構造は基本的にKeyedSubTree、AutomaticKeepAlive、KeepAliveなどであり、ListViewのビルド時に各アイテムにラップされます。詳細な原則はFlutter Enhanced List-ListView PerformanceAnalysisに記載されています。
したがって、ラグの原因は非常に明白です。主な理由は、特定のフレームで、ListViewが複数の複雑なアイテムを作成することです。たとえば、分析図では、レイアウトフェーズで複数のアイテムが同時に作成されます。アイテムの作成には10ミリ秒近くかかり、同時に作成されるのは当然16ミリ秒を超えます。
3.吃音が発生しやすいシーンはどれですか?
ListViewのCatonの原因がわかったので、Catonが主に発生するのはいつですか。私自身のテスト結果と組み合わせると、主に次の3つの段階にあります。
- 1.リストが作成されたときに初めて入力します
ListViewで作成されたページを開くと、現時点ではListViewにアイテムがないため、複数回作成されます。これは、上記の例の130msの場合です。
- 2.すばやくスワイプして、1つのフレームに複数のアイテムを作成します
高速スライディングの過程では、スライディング範囲が比較的広いため、複数のアイテムが作成される可能性もあります。
- 3.さらにロードするようにSetState
3番目のシナリオは、一部のページングリストにあります。データ要求の完了後にsetState()でリストを更新し、最後にListViewの対応する要素のperformRebuild()を呼び出すことがよくあります。
_childElementsはキャッシュされたアイテムノード(つまり、現在の画面とキャッシュ領域にあるすべてのアイテム)であり、各アイテムはここで更新されます。同時に、子ノードの数が増える(アイテムの数が増える)ため、新しいアイテムが作成されますが、これも遅れがちです。
3. ListViewの遅延を最適化する方法は?
最適化のアイデア
1.フレーム単位の画面
吃音の本質的な理由は、モジュールの実行時間が1フレームで長すぎることです。これは、ListViewの問題であるだけでなく、複雑な要素を持つすべてのページが同じです。では、この問題に対する一般的な解決策はありますか?実際、答えは非常に単純です。2つの方法で考えることができます。最初のタイプの 最適化モジュール時間(Androidでのレイアウト最適化など) では、モジュールの原因が原因で、特定の問題の特定の分析が必要です。ストールは多様であり、ウィジェットが複雑すぎる、適切な部分更新がない、またはUI分離が多くの計算を実行しているなどの可能性があります。2番目のアイデアは、モジュールを最適化せずに時間をスライスして流暢さを向上させることです。 これは、一般にフレーム操作として知られています。原理を理解するための図:
画面に4つのアイテムを表示でき、各アイテムの作成に10ミリ秒かかるとします。既存のListViewレイアウトプロセスでは、これらの4つのアイテムは、最初のフレームで同時に作成され、合計で40ミリ秒になります。
フレーミングを使用した後、ページの最初のフレームで、最初に単純なプレースホルダーアイテムを作成します。プレースホルダーアイテムは単純なコンテナーにすることができます。基本的に構築に時間がかからないため、最初のフレームで4つのコンテナを構築してもフリーズは発生しません。その後、実際の4つのアイテムは、レンダリングのために次の4フレームに遅延されます。このようにして、16.7ミリ秒ごとに、タイムアウトレンダリングが発生せず、プロセス全体がスタックすることはありません。
これは、画面にフレームされた後のユーザーエクスペリエンスに影響しますか?大きな工場が言ったことを見てください:
経験上、リストコントロールの構造について言えば、目に見えないキャッシュ領域があることがわかっているので、フレーム画面のほとんどはこの目に見えない領域で完成します。このため、ユーザーは高い認識を持っていません。エンドマシンまたは通常のスライド状態。ローエンドのマシンでは、すばやくスワイプすることでカードの空白の状況をはっきりと見ることができますが、全体的な感覚は深刻な欲求不満よりも優れています。
この期間中の私のテストと組み合わせると、このソリューションは実際にはハイエンドデバイス(テストデバイス:OnePlus 7Pro)(実装ソリューションに関連)にほとんど影響を与えず、最適化はローエンドデバイスで明らかであり、ほとんどあります使用プロセスに遅れはありません。
2.LoadMoreインクリメンタルアップデート
上で述べたように、アイテムの構築はListViewのレイアウトによって駆動されるため、増分更新の場合は、itemCountを変更し、ListViewにレイアウトのマークを付けるだけで済みます。Xianyuは記事でウィジェットキャッシュをレイアウト前に更新する必要があると述べましたが、実際には、1.22以降、このキャッシュには最適化効果がほとんどないため、公式はウィジェットキャッシュを削除し、プロセスが簡単になりました。
3.要素の再利用?
Xianyuはまた、1つの記事の1つのポイント、つまり要素の再利用についても言及しました。この最適化のポイントについてlwlizheと連絡を取り合った後、私は個人的にその効果はそれほど明白ではないかもしれないと思います。ネイティブの観点からViewHolderを例にとると、その再利用の本質は、ビューの作成と同じタイプのアイテムのxmlの解析にかかる時間を短縮することです。その中には、重要なメソッドがあります。onBindViewHolderはデータをにバインドします。景色。
ただし、Flutterの場合、アイテムが同じタイプであっても、データが異なるアイテムのデータバインディングウィジェットメソッドはありません。したがって、要素を保存するためのバッファプールを構築し、作成時に最初にキャッシュから取得することしかできません。しかし、これが問題です。実際、cacheExtentに要素をキャッシュするcacheExtentキャッシュ領域の設計があります。個人的には、追加のキャッシュはあまり必要ないと思います。最も簡単なのは、cacheExtentをより大きな値に設定することです。
実行計画
基本的な考え方で、この機能を実現するにはどうすればよいでしょうか。主にフレームスクリーンの実現についてみんなに話してください。
サブフレームの画面は単なるプレースホルダーであり、実際のウィジェットを置き換えますが、重要な点はどのようにフレーミングするかです。
ここでは、条件付きフレーミングタスクキューを使用して実現され、その原理が図に示されています。
まず、システム自体のレンダリングプロセスに影響を与えないように、タスクは現在の分離のキューに追加され、システムがレンダリングやその他のトランザクションを終了した後にタスクがスケジュールされます。ただし、タスクはすぐには実行されませんが、特定の条件を満たす必要があります。システムのアプローチを参照すると、重み値の列挙があります。各タスクの重み値を定義します。これは、対応する条件が満たされた場合にのみ実行できます。 。
たとえば、タスクの重みがPriority.idleの場合、そのようなタスクは、(定義されたスケジューリング戦略に関連して)完全にアイドル状態のときにのみ実行されます。この時点で画面に中断のないアニメーションがある場合、タスクキュー全体がブロックされます。
タスクは非常に単純で、プレースホルダーウィジェットを実際の子に置き換えることですが、ここでのプレイアビリティは非常に高くなっています。
直接交換するのが最も簡単な方法です。読み込みプロセスを強調するために、プレースホルダーと実際のアイテムを対照的な色に変更しました。実際の使用では、アイテムのスタイルに応じて同様のプレースホルダーウィジェットを設定できます。効果が良いです。
これは少し鈍く見えます、私たちは彼に透明度の変更を加えることができます〜
または、左から右にスライドさせましょう〜
OHHHHHHHHHHH
実際、プロセス全体を見ることができます。プリロードのためにゆっくりスライドすると、ウィジェットの切り替えプロセスを見ることができません。高速スライドの過程で、1フレームの残業レンダリングが発生することがありますが、そのピーク値は以前の半分近く低くなり、全体的なfpsは非常に安定しており、スライドプロセス中に明らかな一時停止感はありません。
ただし、多くのアニメーションが追加されているため、一部のUIがフリーズする可能性があります〜HAHAHAHHA
リストされていない4つのラグソリューション
建設クラスによって引き起こされる吃音については、複雑なフレームを複数のフレームに分解して吃音を最適化することもできます。栗のカンカンを見てみましょう。
[画像のアップロードに失敗しました...(image-74ccd0-1616072584878)]
複雑なページは複雑な要素で構成されている必要があります。ここでは、列に複数の行を配置し、各行に複数の複雑なウィジェットを配置します。このような例では、各行モジュールのフレーミングウィジェットをネストし、各行にフレーミングレンダリングを実行させることができます。実際の最適化効果は次のとおりです。
これはページの水平方向の最適化用です。同じ方法を使用して、複雑なウィジェットの垂直方向の最適化を最適化できます。ここでは例を示しません〜
5.現在のプロファイルモードでのパフォーマンス最適化データ:
初めてリストを入力すると、建物のパフォーマンスが90%向上しました
高速スワイプにほとんど遅れはありません
ロードするとパフォーマンスが80%向上します
メモリ比較
ListView高速スライド
BKListView高速スライド
また、これらは私が暇なときに何度も何度も読む素晴らしい資料であることをあなたと共有します。近年の主要工場へのインタビューの高頻度知識ポイントについて詳細な説明があります。誰もが知識を習得し、原則を理解するのに効果的に役立つと思います。アウトラインを無料で入手
Android学習PDF +アーキテクチャビデオ+インタビュードキュメント+ソースノート、高度なアーキテクチャテクノロジーの高度なマインドマップ、Android開発のインタビュートピック資料、高度な高度なアーキテクチャ資料、それを必要とする友人は[パッケージに追加して入手]できます。
著者:なゆた
リンク:
https ://juejin.cn/post/6940134891606507534
出典:ナゲッツ