<

パフォーマンスのベストプラクティス

通常、Flutter アプリケーションはデフォルトでパフォーマンスが高くなりますが、 したがって、優れた成果を上げるには、よくある落とし穴を避けるだけで済みます パフォーマンス。これらのベスト プラクティスに関する推奨事項は、次のような場合に役立ちます。 可能な限り最もパフォーマンスの高い Flutter アプリを作成します。

Flutter アプリを最も効率的に設計するにはどうすればよいですか シーンをレンダリングしますか?特に、どのように保証しますか によって生成されたペイント コード フレームワークは可能な限り効率的ですか? いくつかのレンダリングおよびレイアウト操作が知られています 遅くなりますが、常に回避できるわけではありません。 それらは慎重に使用する必要があります。 以下のガイダンスに従ってください。

コストのかかる操作を最小限に抑える

一部の操作は他の操作よりも高価です。 つまり、より多くのリソースを消費します。 明らかに、これらの操作のみを使用したいと考えます。 必要に応じて。どのように設計して実装するか アプリの UI は、アプリの実行効率に大きな影響を与える可能性があります。

build() コストの制御

UI を設計する際に留意すべき点がいくつかあります。

  • 反復的でコストのかかる作業を回避するbuild()メソッド 以来build()次の場合に頻繁に呼び出すことができます 祖先ウィジェットが再構築されます。
  • 単一のウィジェットが大きすぎることは避けてください。build()関数。 カプセル化に基づいてそれらを異なるウィジェットに分割します だけでなく、それらがどのように変化するかについても説明します。
    • いつsetState()に呼ばれますState物体、 すべての子孫ウィジェットが再構築されます。したがって、 をローカライズするsetState()~の部分に電話する 実際に UI を変更する必要があるサブツリー。 電話は避けるsetState()木の高いところに 変更がツリーの小さな部分に含まれている場合。
    • すべての子孫を再構築するための走査は、次の時点で停止します。 前と同じ子ウィジェットのインスタンス フレームが再会しました。このテクニックは重いです 最適化のためにフレームワーク内で使用されます アニメーションが子サブツリーに影響を与えないアニメーション。 を参照してください。TransitionBuilderパターンと ののソースコードSlideTransition、 この原則を使用して、再構築を回避します。 アニメーション化するときの子孫。 (「同じインスタンス」は次のように評価されます)operator ==、 ただし、このページの最後にある落とし穴のセクションを参照してください。 オーバーライドを避けるべき場合についてのアドバイスoperator ==。)
    • 使用const可能な限りウィジェットのコンストラクターを使用し、 Flutter がほとんどの回路をショートさせることができるため、 建て替え工事の様子。自動的にリマインドされるようにするには 使用するconst可能であれば、 からの推奨リントflutter_lintsパッケージ。 詳細については、以下をご覧ください。flutter_lints移行ガイド
    • 再利用可能な UI を作成するには、 を使用することを好みますStatelessWidget関数ではなく。

詳細については、以下をご覧ください。

  • パフォーマンスに関する考慮事項、 の一部StatefulWidgetAPIドキュメント
  • ウィジェットとヘルパー メソッドの比較、 公式 Flutter YouTube からのビデオ ウィジェットの理由を説明するチャンネル (特にウィジェットconstコンストラクター) 関数よりもパフォーマンスが優れています。

saveLayer() は慎重に使用してください

一部の Flutter コードでは、saveLayer()、高価な操作、 UI にさまざまな視覚効果を実装します。 コードが明示的に呼び出していない場合でも、saveLayer()、 使用する他のウィジェットやパッケージは、それを舞台裏で呼び出す場合があります。 おそらくアプリが呼び出しているのでしょうsaveLayer()必要以上に; ~への過剰な電話saveLayer()ジャンクの原因となる可能性があります。

saveLayer はなぜ高価なのでしょうか?

電話をかけるsaveLayer()オフスクリーンバッファを割り当てます オフスクリーン バッファにコンテンツを描画すると、 レンダー ターゲット スイッチをトリガーします。 GPU は消火ホースのように実行したいのですが、 レンダー ターゲットの切り替えにより GPU が強制的に使用されます。 そのストリームを一時的にリダイレクトしてから もう一度元に戻します。モバイル GPU ではこれは次のとおりです 特にレンダリングのスループットに影響を及ぼします。

saveLayer が必要になるのはどのような場合ですか?

実行時にさまざまな形状を動的に表示する必要がある場合 (たとえば) サーバーから送信され、それぞれにある程度の透明性があり、 重複するかもしれない(または重複しないかもしれない)、 それからあなたはかなり使う必要がありますsaveLayer()

saveLayer への呼び出しのデバッグ

アプリの呼び出し頻度を確認するにはどうすればよいですかsaveLayer()、 直接的か間接的か? のsaveLayer()メソッドトリガー のイベント開発ツールのタイムライン;いつ学ぶか あなたのシーンで使用されているsaveLayerをチェックすることでPerformanceOverlayLayer.checkerboardOffscreenLayersに切り替えますDevTools のパフォーマンス ビュー

saveLayer の呼び出しを最小限に抑える

への電話を避けてもらえますかsaveLayer? やり方を再考する必要があるかもしれません 視覚効果を作成します。

  • から電話がかかってくる場合あなたのコード、できますか それらを減らすか排除しますか? たとえば、UI が 2 つの図形に重なっているとします。 それぞれがゼロ以外の透明度を持ちます。
    • 常に同じ量だけ重なると、 同じように、同じ透明度で、 これが何と重なっているかを事前に計算できます。 半透明のオブジェクトは次のようになります、それをキャッシュします、 呼び出す代わりにそれを使用してくださいsaveLayer()。 これは、事前に計算できるあらゆる静的形状で機能します。
    • ペイントロジックをリファクタリングして回避できますか 全部重なってる?
  • 自分が所有していないパッケージから通話が発信されている場合は、 パッケージの所有者に連絡して理由を尋ねます これらの呼び出しは必要です。削減できるか、それとも 排除された?そうでない場合は、別のものを探す必要があるかもしれません パッケージ化するか、独自に作成します。

トリガーされる可能性のあるその他のウィジェットsaveLayer()潜在的にコストがかかる:

  • ShaderMask
  • ColorFilter
  • Chip— への呼び出しをトリガーする可能性がありますsaveLayer()もしもdisabledColorAlpha != 0xff
  • Text— への呼び出しをトリガーする可能性がありますsaveLayer()あるならoverflowShader

不透明度とクリッピングの使用を最小限に抑える

不透明度もクリッピングと同様に高価な操作です。 役立つヒントをいくつか紹介します。

  • 使用Opacity必要な場合のみウィジェットを使用できます。 を参照してください。透明な画像セクションのOpacity不透明度を直接適用する例の API ページ 画像への変換は、Opacityウィジェット。
  • 単純な図形やテキストを折り返す代わりに でOpacityウィジェットの場合、通常はこの方が速いです 半透明の色で描くだけです。 (ただし、これは重複がない場合にのみ機能します 描画される形状のビット)。
  • 画像のフェードインを実装するには、FadeInImage段階的な効果を適用するウィジェット GPU のフラグメント シェーダーを使用して不透明度を調整します。 詳細については、以下をご覧ください。Opacityドキュメント。
  • クリッピング電話をかけないsaveLayer()(そうでもなければ 明示的にリクエストされたClip.antiAliasWithSaveLayer)、 したがって、これらの操作はそれほど高価ではありませんOpacity、 ただし、クリッピングには依然としてコストがかかるため、使用には注意が必要です。 デフォルトでは、クリッピングは無効になっています(Clip.none)、 したがって、必要に応じて明示的に有効にする必要があります。
  • 角の丸い長方形を作成するには、 クリッピング長方形を適用する代わりに、 の使用を検討してくださいborderRadius提供された物件 多くのウィジェット クラスによって使用されます。

グリッドとリストを慎重に実装する

グリッドとリストの実装方法 アプリのパフォーマンス上の問題を引き起こしている可能性があります。 このセクションでは、重要なベストについて説明します。 グリッドやリストを作成するときに練習してください。 アプリが を使用しているかどうかを判断する方法 過剰なレイアウトパス。

怠け者になってください!

大規模なグリッドまたはリストを作成する場合、 コールバックを備えた遅延ビルダー メソッドを使用します。 これにより、表示されている部分のみが確実に表示されます。 画面は起動時に構築されます。

詳細と例については、以下を確認してください。

  • 長いリストの操作の中に料理本
  • の作成ListView一度に 1 ページをロードしますAbdulRahman AlHamali によるコミュニティ記事
  • Listview.builderAPI

組み込み関数を避ける

固有パスがどのような原因で発生する可能性があるかについては、 グリッドとリストに関する問題については、次のセクションを参照してください。


組み込み操作によって発生するレイアウト パスを最小限に抑える

Flutter プログラミングをたくさんやったことがある人なら、 おそらくよく知られているレイアウトと制約の仕組みUIを作成するとき。 Flutter を覚えたことがあるかもしれません 基本的なレイアウトルール:制約が下がります。サイズが上がります。 親が位置を設定します。

一部のウィジェット、特にグリッドとリストの場合、 レイアウトプロセスにはコストがかかる場合があります。 Flutter はレイアウト パスを 1 つだけ実行するように努めます ウィジェット上でも、場合によっては、 2 番目のパス (固有パス)が必要です。 パフォーマンスが低下する可能性があります。

固有パスとは何ですか?

固有のパスは、たとえば次のような場合に発生します。 すべてのセルのサイズを同じにする必要があります 最大または最小のセル(または一部) すべてのセルをポーリングする必要がある同様の計算)。

たとえば、次の大きなグリッドを考えてみましょう。Cards. グリッドには均一なサイズのセルが必要です。 したがって、レイアウト コードはパスを実行します。 (ウィジェット ツリー内の) グリッドのルートから開始して、 尋ねるグリッド内のカード ( 表示されているカード) を返す これは本質的なサイズ—サイズ 制約がないと仮定して、ウィジェットが優先するもの。 この情報により、 フレームワークは均一なセル サイズを決定します。 そして、すべてのグリッド セルを 2 回目に再訪問します。 各カードに使用するサイズを伝えます。

組み込みパスのデバッグ

過剰な固有パスがあるかどうかを判断するには、 を有効にするトラックレイアウトオプションDevTools (デフォルトでは無効)、 そしてアプリを見てみると、スタックトレース実行されたレイアウト パスの数を確認します。 追跡を有効にすると、組み込みのタイムライン イベント 「$runtimeType 組み込み」というラベルが付けられています。

固有のパスの回避

固有のパスを回避するには、いくつかのオプションがあります。

  • 事前にセルを固定サイズに設定します。
  • 特定のセルを選択します。 「アンカー」セル - すべてのセルが このセルに相対的なサイズになります。 カスタム レンダー オブジェクトを作成します。 最初に子アンカーを配置してから配置します 周りの他の子供たちを追い出します。

レイアウトがどのように機能するかをさらに詳しく調べるには、 をチェックしてくださいレイアウトとレンダリングセクションのFlutter アーキテクチャの概要


16ミリ秒でフレームを構築して表示

構築には 2 つの別々のスレッドがあるため、 レンダリングには、ビルドに 16 ミリ秒かかります。 60Hz ディスプレイでのレンダリングには 16ms。 遅延が懸念される場合は、 16msでフレームを構築して表示します以下。 これは 8ms 以下で組み込まれることを意味することに注意してください。 8ミリ秒以下でレンダリングされます。 合計16ms以下。

フレームがかなり下でレンダリングされている場合 合計16ミリ秒プロファイルモード、 おそらくパフォーマンスについて心配する必要はありません たとえパフォーマンス上の落とし穴があったとしても、 しかし、それでも構築することを目指すべきです。 フレームをできるだけ速くレンダリングします。なぜ?

  • フレームのレンダリング時間を 16 ミリ秒未満にすると、ビジュアルが表示されなくなる可能性があります。 違いますが、それはバッテリー寿命を向上させるそして熱の問題。
  • お使いのデバイスでは問題なく動作する可能性がありますが、デバイスのパフォーマンスを考慮してください。 ターゲットとする最も低いデバイス。
  • 120fps デバイスがより広く入手可能になるにつれて、 フレームを 8 ミリ秒未満 (合計) でレンダリングしたい場合 最もスムーズな体験を提供するために。

なぜ 60fps がスムーズな視覚体験につながるのか疑問に思っているなら、 ビデオをチェックしてくださいなぜ60fpsな​​のか?

落とし穴

アプリのパフォーマンスを調整する必要がある場合は、 あるいは、UI が期待したほどスムーズではない可能性があります。 のDevTools のパフォーマンス ビュー助けられる!

また、IDE の Flutter プラグインは、 便利である。 「 flutterパフォーマンス」ウィンドウで、 を有効にするウィジェットの再構築情報を表示チェックボックス。 この機能は、フレームがいつ停止されるかを検出するのに役立ちます。 レンダリングと表示に 16 ミリ秒以上かかります。 可能であれば、 プラグインは、関連するヒントへのリンクを提供します。

次のような行為は悪影響を与える可能性があります アプリのパフォーマンス。

  • の使用は避けてください。Opacityウィジェット、 特にアニメーションでは避けてください。 使用AnimatedOpacityまたFadeInImageその代わり。 詳細については、こちらをご覧ください不透明度アニメーションのパフォーマンスに関する考慮事項。

  • を使用するときは、AnimatedBuilder、 ビルダーにサブツリーを入れないようにする そうでないウィジェットを構築する関数 アニメーションに依存します。このサブツリーは アニメーションのティックごとに再構築されます。 代わりに、サブツリーのその部分を構築します 一度それを子として渡します のAnimatedBuilder。詳細については、 チェックアウトパフォーマンスの最適化。

  • アニメーション内のクリッピングを避けてください。 可能であれば、アニメーション化する前に画像を事前にクリップしてください。

  • 具体的なコンストラクターの使用を避けるList子どもたちの(たとえば、Column()またListView()) ほとんどの子供たちが見えない場合 構築コストを回避するために画面上に表示されます。

  • オーバーライドを避けるoperator ==の上Widgetオブジェクト。 不必要な再構築を避けることで役立つように思えるかもしれませんが、 実際には、O(N²) 動作が発生するため、パフォーマンスが低下します。 このルールの唯一の例外は、リーフ ウィジェット (子のないウィジェット) です。 ウィジェットのプロパティを比較する特定のケースでは ウィジェットを再構築するよりも大幅に効率的である可能性があります ウィジェットの設定がほとんど変更されない場合。 そのような場合でも、 一般的にはウィジェットのキャッシュに依存することが望ましいですが、 なぜなら、たとえ1つのオーバーライドでもoperator ==全体的なパフォーマンスの低下を引き起こす可能性があります コンパイラは呼び出しが常に静的であると想定できなくなるためです。

資力

パフォーマンスの詳細については、次のリソースを確認してください。

  • パフォーマンスの最適化AnimatedBuilder API ページ内
  • 不透明度アニメーションのパフォーマンスに関する考慮事項Opacity API ページ内
  • 子要素のライフサイクルそれらを効率的にロードする方法、 ListView API ページ内
  • パフォーマンスに関する考慮事項のStatefulWidget