web-dev-qa-db-ja.com

LogcatのChoreographerメッセージの意味

SDK (API 16)の最新版をインストールし、最新のADTを入手しました。私は今、logcatにこれらのメッセージを見ています。確かに、私は前に見たことがありません。誰もがこれについての考えを持っていますか?

06-29 23:11:17.796:I/Choreographer(691):647フレームスキップしましたアプリケーションがそのメインスレッドでやり過ぎている可能性があります。

私は検索をして、このリンクを見つけました: http://developer.Android.com/reference/Android/view/Choreographer.html 。これはAPI 16で導入された新しいクラスです。

私の処理はすべてAsyncTasksで行われているため、私のアプリケーションがどのような "やり過ぎる"作業を行っているのかを判断する方法を知る必要があります。

194
Code Poet

Choreographerを使用すると、アプリでvsyncに接続し、適切なタイミングでパフォーマンスを向上させることができます。

Androidのビューアニメーションは、内部的に同じ目的でChoreographerを使用します。アニメーションのタイミングを適切に設定し、パフォーマンスを向上させるためです。

Choreographerはすべてのvsyncイベントについて通知されるので、Choreographer.post * apisによって渡されたRunnablesの1つが1フレームの時間内に完了しないためにフレームがスキップされるのかどうかを判断できます。

私の理解では、Choreographerはフレームスキップを検出することしかできません。なぜこれが起こるのかを知る方法はありません。

メッセージ「アプリケーションはメインスレッドで作業しすぎている可能性があります」誤解を招く可能性があります。

132
CuriousChettai

私はパーティーに遅れています、しかしうまくいけばこれはここに他の答えへの役に立つ追加です...

質問に答える/ tl:dr;

私の処理はすべてAsyncTasksで行われているので、私はどのようにして私のアプリケーションが何をしているのかを判断する必要があります。

以下はすべて候補です。

  • メインスレッドでのIOまたは高価な処理(ドロアブルの読み込み、レイアウトの拡張、およびUriname__の設定ImageViewname__はすべてメインスレッドのIOを構成します)
  • 大きい/複雑な/深いViewname__階層のレンダリング
  • Viewname__階層の大部分を無効にする
  • カスタムonDrawname__内の高価なViewname__メソッド
  • アニメーションでの高価な計算
  • "ワーカー"スレッドを "バックグラウンド"と見なすには高すぎる優先度で実行しています(AsyncTaskname__はデフォルトで "background"です。Java.lang.Threadnot
  • 大量のゴミを生成し、それがクリーンアップしている間、ガベージコレクタに「世界を止めさせる」(メインスレッドを含む)ことを引き起こす

特定の原因を実際に判断するには、アプリケーションのプロファイルを作成する必要があります。

より詳しく

私は試して、 code を見て、Choreographerを理解しようとしています。

Choreographerのドキュメンテーションは、「アニメーション、入力、および描画のタイミングを調整する」で始まります。これは実際には良い説明ですが、残りはアニメーションを強調しすぎます。

Choreographerは、実際には次の順序で実行される3種類のコールバックを実行する責任があります。

  1. 入力処理コールバック(タッチイベントなどのユーザー入力の処理)
  2. フレーム間のトゥイーン用のアニメーションコールバック。実行中のすべてのアニメーションに安定したフレーム開始時間を提供します。これらのコールバックを2回実行すると、3番目のタイプのコールバックが呼び出されるまでに、アニメーション関連の計算(ビューの位置の変更など)が既に行われていることを意味します。
  3. ビュー階層を描画するためのビュートラバーサルコールバック。

目的は無効化されたビューが再描画される(そしてアニメーションがトゥイーンされる)レートをスクリーンのvsync(通常は60fps)に合わせることです。

スキップされたフレームに関する警告は後付けのように見えます:singleが3つのステップを通過するときにメッセージが記録されるのは予想されるフレーム期間の30倍以上です。ログメッセージに「スキップされた30frames」と表示されることがあります。eachpassの場合、30フレームスキップする必要がある場合よりも50%長くなります(いたずら!)それについて警告されません。

3つのステップから、警告を引き起こすことができるのはアニメーションだけではないことが明らかになりました。複雑なonDrawメソッドを使用して、大規模なViewname__階層またはViewname__の大部分を無効にすることで十分です。

例えばこれは繰り返し警告を引き起こします:

public class AnnoyTheChoreographerActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.simple_linear_layout);

        ViewGroup root = (ViewGroup) findViewById(R.id.root);

        root.addView(new TextView(this){
            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
                long sleep = (long)(Math.random() * 1000L);
                setText("" + sleep);
                try {
                    Thread.sleep(sleep);
                } catch (Exception exc) {}
            }
        });
    }
}

...これは次のようなログを生成します。

11-06 09:35:15.865  13721-13721/example I/Choreographer﹕ Skipped 42 frames!  The application may be doing too much work on its main thread.
11-06 09:35:17.395  13721-13721/example I/Choreographer﹕ Skipped 59 frames!  The application may be doing too much work on its main thread.
11-06 09:35:18.030  13721-13721/example I/Choreographer﹕ Skipped 37 frames!  The application may be doing too much work on its main thread.

onDrawname__の間のスタックから、あなたがアニメ化しているかどうかにかかわらず、振付家が関与していることがわかります。

example.AnnoyTheChoreographerActivity $ 1.onDraw(AnnoyTheChoreographerActivity.Java:25)にAndroid.view.View.draw(View.Java:13759)

...かなりの繰り返し...

android.widgetのAndroid.view.ViewGroup.drawChild(ViewGroup.Java:3169)でAndroid.view.ViewGroup.dispatchDraw(ViewGroup.Java:3039)でAndroid.view.View.draw(View.Java:13762)で。 Androidの場合はcom.Android.internal.policy.impl.PhoneWindowの$ DecorView.draw(PhoneWindow.Java:2396)の場合はFrameLayout.draw(FrameLayout.Java:467)が表示されます。 Android.viewでのAndroid.view.HardwareRenderer $ GlRenderer.draw(HardwareRenderer.Java:1144)でのview.View.getDisplayList(View.Java:12754)。 Android.view.ViewRootImpl.doTraversal(ViewRootImpl.Java:1112)でのAndroid.view.ViewRootImpl $ Trar.RunでのViewRootImpl.performDraw(ViewRootImpl.Java:2145) (ViewRootImpl.Java:4472)Android.view.Choreographer $ CallbackRecord.run(Choreographer.Java:725)at Android.view.Choreographer.doCallbacks(Choreographer.Java:555) .view.Choreographer.do Frame(Choreographer.Java:525)at Android.view.Choreographer $ FrameDisplayEventReceiver.run(Choreographer.Java:711)at Android.os.Handler.handleCallback(Handler.Java:615)at Android.os.Landper.dispatchMessage(Handler.Java:92)at Android.os.Looper.loop(Looper.Java:137)at Android.app.ActivityThread.main(ActivityThread.Java:4898)

最後に、メインスレッドが処理できる作業量を減らす他のスレッドとの競合がある場合、実際にメインスレッドで作業をしていなくても、フレームをスキップする可能性が劇的に高まります。

この状況では、アプリケーションがメインスレッドでやり過ぎていることを示唆するのは誤解を招くと考えられるかもしれませんが、 Androidはメインスレッドを飢えさせないようにするためにワーカースレッドの優先順位を低くしたい 。ワーカースレッドの優先順位が低い場合、Choreographerの警告を表示する唯一の方法は、メインスレッドでやり過ぎることです。

64
Stevie

これはInfoメッセージが多くの状況であなたのLogCatに現れる可能性がある場合です。

私の場合は、プログラムでXMLレイアウトファイルから複数のビューを展開していたときに起こりました。メッセージ自体は無害ですが、後からAppが使用できるRAMすべてが使用され、巨大なForce Closeが発生するという問題が発生している可能性があります。私は彼のLog WARN/INFO/ERROR Freeを見ることを好む一種の開発者に成長しました。 ;)

だから、これは私自身の経験です:

私はメッセージを得ました:

10-09 01:25:08.373: I/Choreographer(11134): Skipped XXX frames!  The application may be doing too much work on its main thread.

... XMLからビューを膨らませ、そのフィールド(画像、テキストなど)にREST /の応答からのデータを取り込むことによって、私独自のカスタム「超複雑マルチセクションリスト」を作成したときJSON Webサービス(ページング機能なし)は、これらすべてを正しい順序でLinearLayoutに追加することによって、行、サブセクションヘッダー、およびセクションヘッダーとして機能します(ScrollView内で垂直方向)。クリック可能な要素を持つlistViewをシミュレートするためのすべてのこと...しかし、それは別の質問です。

責任ある開発者として、システムリソースを使ってアプリを本当に効率的にしたいので、リストのベストプラクティスは(リストがそれほど複雑ではない場合)、ListActivityまたはListFragmentをLoaderで使用し、ListViewをアダプタで埋めることです。これはおそらくもっと効率的です、実際それはそうです、そしてあなたはいつもそれをやるべきです…あなたのリストがそれほど複雑でないならば。

解決策:私は自分のREST/JSON Webサービスにページングを実装して「大きなレスポンスサイズ」を防ぎ、メインを維持するためにAsyncTaskに「rows」、「section headers」および「sub-section headers」ビューを追加したコードをラップしました。クールスレッド。

だから...私の経験が、このInfoメッセージで頭を割っている他の誰かに役立つことを願っています。

ハッピーハッキング!

24
Oscar S.

私の場合は、シャーロックのアクションバーを表示しているときにこれらのメッセージが表示されます。私のライブラリではないので、私はChoreographerの出力を隠すことにしました。

このフィルター式を使用して、Choreographerの出力をLogcatビューに隠すことができます。

タグ:^((?! Choreographer)。*)$

私は他の場所で説明された正規表現を使いました: 単語を含まない行にマッチするための正規表現?

11
Julien

これは通常、エミュレータを使用してデバッグするときに発生します。エミュレータはとにかく遅いことが知られています。

11
Buzz