アプリケーションがメインスレッドで実行している作業が多すぎる可能性があります


379

Android SDK / API環境は初めてです。それは私がプロット/チャートを描こうとしている最初のものです。3種類の無料ライブラリを使用して、さまざまな種類のサンプルコードをエミュレータで実行してみましたが、レイアウト画面には何も表示されません。logcatは次のメッセージを繰り返しています。

 W / Trace(1378):nativeGetEnabledTagsからの予期しない値:0
 I / Choreographer(1378):55フレームをスキップしました!アプリケーションがメインスレッドで実行している作業が多すぎる可能性があります。

問題が解決せず、ライセンスされたライブラリの評価版に関連するサンプルコードを実行したときにグラフが機能しました。


2
別のスレッドでグラフを描画していますか?
アレクス2013

コメントありがとうございます。質問をより明確にするために編集しました。実行中のアクティビティは、レイアウトのデザインがないアクティビティを実行していることを示しています=>白い画面が表示されています。
user2038135 2013

1
@Areksいいえ、別のスレッドを使用していません。
user2038135 2013

1
メインスレッドで長い操作を実行することはお勧めしません。アプリケーション全体がフリーズするため、スレッドの使用方法をここで読むことができます:stackoverflow.com/questions/3391272/… 「実行するコードを無視するHTTPリクエスト」にアクセスし、潜在的に長い操作をそこで実行するだけです。
2013

1
どうして検索しないと振付家の情報が見つかるのか。私はこの答えを読んですることをお勧めいたします:stackoverflow.com/questions/11266535/...
ガブリエル・エステバン

回答:


479

取得元:Android UI:スキップされたフレームの修正

Androidアプリケーションの開発を始めると、logcatの「Choreographer(abc):Skipped xx frames!アプリケーションがメインスレッドで実行している作業が多すぎる可能性があります。」それが実際に何を意味するのか、なぜ心配する必要があるのか​​、そしてそれをどのように解決するのか。

これは、コードの処理に時間がかかり、そのためフレームがスキップされていることを意味します。おそらく、アプリケーションまたはDBアクセスの中心で実行している重い処理、またはスレッドの原因となるその他の処理が原因です。しばらく停止します。

これはより詳細な説明です:

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

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

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

私の理解では、振付師はフレームのスキップのみを検出できます。これがなぜ起こるかを伝える方法はありません。

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

出典: LogcatにおけるChoreographerメッセージの意味

なぜ心配する必要があるのか

このメッセージがAndroidエミュレーターでポップアップし、スキップされたフレームの数がかなり少ない(<100)場合、エミュレーターが低速であることに安全に賭けることができます。これはほとんど常に発生します。しかし、スキップされたフレームの数が多く、300以上のオーダーの場合、コードに深刻な問題が発生する可能性があります。Androidデバイスは、iOSやWindowsデバイスとは異なり、さまざまなハードウェアで提供されます。RAMとCPUはさまざまで、すべてのデバイスで妥当なパフォーマンスとユーザーエクスペリエンスが必要な場合は、この問題を修正する必要があります。フレームがスキップされると、UIは遅く、遅延します。これは、望ましいユーザーエクスペリエンスではありません。

それを修正する方法

これを修正するには、長時間の処理が発生する、または発生する可能性のあるノードを特定する必要があります。最良の方法は、メインUIスレッドとは別のスレッドでどんなに小さくても大きくてもすべての処理を実行することです。したがって、SQLiteデータベースからデータにアクセスしたり、ハードコア計算を行ったり、単純に配列を並べ替えたりすることができます。別のスレッドで実行してください。

ここで問題があります。これらの操作を行うための新しいスレッドを作成し、アプリケーションを実行すると、「ビュー階層を作成した元のスレッドのみがそのビューにアクセスできる」と言ってクラッシュします。AndroidのUIはメインスレッドまたはUIスレッドによってのみ変更できるというこの事実を知る必要があります。そうしようとする他のスレッドは失敗し、このエラーでクラッシュします。実行する必要があるのは、runOnUiThread内に新しいRunnableを作成することです。このrunnable内で、UIに関連するすべての操作を実行する必要があります。ここで例を見つけます

それで、メインのスレッドからデータを処理するためのThreadとRunnableがあります。AndroidにはAsyncTaskがあり、UIスレッドで長時間のプロセスを実行できます。これは、アプリケーションがデータ駆動型またはWeb API駆動型である場合、またはCanvasを使用して構築されるような複雑なUIを使用する場合に最も役立ちます。AsyncTaskの威力は、バックグラウンドで処理を実行できることです。処理が完了すると、遅れて影響を与えることなく、UIで必要なアクションを実行できます。AsyncTaskはアクティビティのUIスレッドから派生しているため、これが可能です。AsyncTaskを介してUIで行うすべての操作は、メインUIスレッドとは別のスレッドであり、ユーザーの操作に支障はありません。

だから、これはあなたがスムーズなアンドロイドアプリケーションを作るためにあなたが知る必要があることであり、私が知る限り、すべての初心者が彼のコンソールでこのメッセージを受け取ることを知っています。


41
ボタンをクリックすると、ボタンの背景画像が変化し、ボタンがクリックできないアプリがあります。私はどのように多くの仕事をしていますか:(
Remian8985

1
@ Remian8985-ボタンの背景画像の変更(この画像をダウンロードしていると想定)は、AsyncTaskで行う必要があります。つまり、ダウンロードのバックグラウンド操作を実行し、UIスレッドで結果を公開します(画像を提供します)。Androidリファレンスリンクを参照
BenJaminSila

11
@BenJaminSilaはAsyncTaskで背景を変更しますか?本当に?
user25

11
@ user25 "この画像をダウンロードしていると仮定します"
forresthopkinsa

「このメッセージがAndroidエミュレーターでポップアップし、スキップされたフレームの数がかなり少ない(100未満)場合、エミュレーターが遅いので安全な策を講じることができます。」これは現在も当てはまりますか?エミュレータはかなり速くなっていますか?
Robin Dijkhof

243

他の人が上記で答えたように、「55フレームをスキップしました!」アプリケーションで重い処理が行われていることを意味します。

私の場合、アプリケーションに重いプロセスはありません。私はすべてをダブルとトリプルでチェックして、それらのプロセスを削除しました。

スケルトンだけが残るまで、フラグメント、アクティビティ、ライブラリを削除しました。しかし、それでも問題は消えませんでした。リソースを確認することにしました。リソースのサイズを確認するのを忘れていたため、使用しているアイコンや背景がかなり大きいことがわかりました。

だから、私の提案は、上記の答えのどれも役に立たない場合は、リソースファイルのサイズを確認することもできます。


1
私のためにも働いた。ほとんど作業をしていなかったが、遅くて遅いアプリケーションを使用していました。スキップされたフレームログが何度も表示される。活動から背景を取り除いたら、すべてうまくいきました。ありがとう!
akrabi 2016年

正解です。これはまさに私の問題でした。他の(かなり複雑な)ソリューションをたくさん試しましたが、アプリの速度も同じくらい遅かったです。私はすべてのWebサービスを取り出し、コードを徹底的に最適化しようとしました。うまくいきませんでした、そして私はこれを見ました。背景画像(私が持っている最大の画像)を削除するとすぐに、古い「遅い」コードを使用していても、アプリはクリックするのと同じくらい速く動作します。
Mバルボサ

あなたは私の日を作りました!
Nicolas Mastromarino 2017年

:)あなたは絶対的な天才です。
Metin Ilhan 2017

@batshevaは1 KBである必要はありません。それはあなたのニーズに依存します、より鮮明な画像が必要だとしましょう、あなたはより高い解像度を使用するかもしれませんが、リソースの異なるフォルダに異なるサイズに分割することを確認してください。
Sithu

61

私も同じ問題を抱えていました。
私の場合は、ドローアブルにある背景画像を使用していました。その特定の画像は約130kBで、Androidアプリのスプラッシュスクリーンとホームページで使用されていました。

解決策 -その特定の画像をdrawablesからdrawables-xxxフォルダーに移動したところ、バックグラウンドで占有されていた多くのメモリを解放でき、スキップするフレームがスキップされなくなりました。

更新「nodp」ドローアブルリソースフォルダーを使用して、バックグラウンドドローアブルファイルを保存します。
密度認定の描画可能なフォルダまたは描画可能なnodpiが優先されますか?


7
大きな背景画像をドローアブルからmimap-xxxhdpiに移動したところ、うまくいきました。
bgplaya 2016年

あなたはたくさん助けてくれました。ありがとう
N.Droid 2017年

2
このソリューションは、トリックを行っています。drawable-xxxhdpi代わりにフォルダを使用していますdrawableが、これにより使用メモリが大幅に削減されます(約70%削減)。また、同じサイズの画面でもDPIサイズは異なります。それらの間のピクセル単位の比はldpi = 1:0.75mdpi = 1:1hdpi = 1:1.5xhdpi = 1:2xxhdpi = 1:3xxxhdpi = 1:4。このdrawable-xxxhdpiフォルダーを使用することで、画像をデバイスの画面サイズに縮小して、メモリとCPUの消費量を削減できます。
TimoBähr2017年

2
からdrawableに画像を移動するとdrawable-nodpi、アプリケーションが取得できなくなりOut of Memory Errorます。
Shruti 2017

ああ、神様…ありがとう!ドローアブルフォルダー内に画像があり、これによりアプリの動作が非常に遅くなりました(画像は100kbしかありませんでしたが!!!)。drawable-xxxファイルを生成した後(私はAndroid Drawable Importerを使用しました)、私のアプリはすごく速いです。どうもありがとう!
error1337

20

UIスレッドの遅延のもう1つの一般的な原因は、SharedPreferencesアクセスです。PreferenceManager.getSharedPreferencesやその他の同様のメソッドを初めて呼び出すと、関連付けられた.xmlファイルがすぐに読み込まれ、同じスレッドで解析されます

この問題に対処する良い方法の1つは、バックグラウンドスレッドから最初のSharedPreferenceロードをトリガーすることです。これは、できるだけ早く開始されます(たとえばonCreate、アプリケーションクラスから)。このようにして、設定オブジェクトは、使用したいときにすでに作成されている場合があります。

残念ながら、起動の初期段階(初期アクティビティやアプリケーション自体など)で設定ファイルを読み取る必要がある場合があります。そのような場合でも、を使用することでUIのストールを回避できMessageQueue.IdleHandlerます。メインスレッドで実行する必要がある他のすべてのことを行い、アクティビティが完全に描画されたら、IdleHandlerをインストールしてコードを実行します。そのRunnableでは、あまりにも多くの描画操作を遅らせたりChoreographerを不満にしたりせずにSharedPreferencesにアクセスできるはずです。


1
この場合、commit()ではなくapply()メソッドを使用することをお勧めします。apply()メソッドはUIをブロックできません。こちらからご覧いただけますdeveloper.android.com/training/data-storage/shared-preferences
EmreGürses

16

アプリのパフォーマンスを向上させるために、次の戦略を試してください。

  • 可能であれば、マルチスレッドプログラミングを使用します。スマートフォンに1つのコアがある場合でも、パフォーマンス上のメリットは非常に大きくなります(プロセッサが2つ以上ある場合、スレッドは異なるコアで実行できます)。アプリのロジックをUIから分離すると便利です。Javaスレッド、AsyncTaskまたはIntentServiceを使用します。これを確認してください
  • Android開発Webサイトのその他のパフォーマンスに関するヒントを読んでそれに従ってください。こちらをチェックしてください

3
最初のリンクでは、アクセスするために「...検証済みのアカウントを持っている...」ことが必要です。
chornge 2018

9

私も同じ問題を抱えていました。Android EmulatorはAndroid <6.0で完全に動作しました。エミュレーターNexus 5(Android 6.0)を使用した場合I/Choreographer: Skipped frames、ログでのアプリの動作が非常に遅くなりました。

だから、私はこのようにマニフェストファイルhardwareAcceleratedオプションを変更することでこの問題を解決しましたtrue

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application android:hardwareAccelerated="true">
        ...
    </application>
</manifest>

8

私はエキスパートではありませんが、AndroidアプリケーションからWebサーバーにデータを送信するときにこのデバッグメッセージが表示されました。AsyncTaskクラスを使用してデータ転送をバックグラウンドで実行しましたが、サーバーから結果データを取得するために、UIを同期させるAsyncTaskクラスのget()メソッドを使用しました。これは、UIが長時間待機することを意味します。したがって、私のアドバイスは、アプリにネットワーク指向のすべてのタスクを個別のスレッドで実行させることです。


6

画像を最適化する... 100KBを超える画像は使用しないでください...画像の読み込みにCPUがかかりすぎて、アプリがハングします。


4
Javaコードで画像のサイズを小さくするか、フォトショップを使用して画像をトリミングします。また、compressor.ioを使用して画像を圧縮します
HarshitG

5

私も同じ問題を抱えていました。私の場合、2つのネストされた相対レイアウトがありました。RelativeLayoutは常に2つの測定パスを実行する必要があります。RelativeLayoutsをネストすると、指数測定アルゴリズムが得られます。


4

これは通常、メインスレッドで巨大なプロセスを実行しているときに発生します。200未満のフレームをスキップしても問題ありません。ただし、スキップしたフレームが200を超える場合は、アプリケーションUIスレッドの速度が低下する可能性があります。あなたができることは、ワーカースレッドと呼ばれる新しいスレッドでこれらのプロセスを実行することです、その後、UIスレッドでアクセスしてsthを実行したい場合(例:ビューで何かを行う、findViewなど...)ハンドラまたはrunOnUiThreadを使用できます(これはもっと好きです)処理結果を表示するため。これは問題を完全に解決します。この場合、ワーカースレッドを使用すると非常に便利です。


1

私も同じ問題を抱えていました。別のコンピューターでコードを実行したところ、問題なく動作しました。しかし、私の場合、「アプリケーションがメインスレッドで実行している作業が多すぎる可能性があります」と表示されていました。

Androidスタジオを再起動して問題を解決しました[ファイル->無効なキャッシュ/再起動-> [無効化して再起動]をクリックします]。


私はあなたの解決策がうまくいった理由を知りません。とにかくありがとう。
Bhuvanesh BS 2018

1

私の場合は、誤ってメソッドにブレークポイントを設定したためです。一度クリアすると、メッセージは消え、パフォーマンスが大幅に向上しました。


0

私のアプリにも同じ問題がありました。しかし、それはカードのリストとその上にテキストを表示する以外に何もしていませんでした。バックグラウンドで実行されているものはありません。しかし、調査の結果、カードの背景に設定された画像が小さい(350kb)にもかかわらず、これが原因であることがわかりました。次に、http: //romannurik.github.io/AndroidAssetStudio/index.htmlを使用して画像を9patch画像に変換しました 。
これでうまくいきました。


0

この問題について多くの研究開発を行った後、私はソリューションを得ました

私の場合、2秒ごとに実行されるServiceを使用していて、runonUIThreadを使用すると、問題はあるがまったくないのではないかと思っていました。私が見つけた次の問題は、May Appで大きな画像を使用していることです。

画像を削除して新しい画像を設定しました。

結論:-コードを調べて、使用している生ファイルがサイズが大きいことを確認します。


0

最初に警告を読んでください。メインスレッドの負荷が高くなっています。つまり、スレッドでより多くの作業を行う関数を実行するだけです。


-1

グリッドレイアウトで多くの描画可能なpngファイルを使用するアプリの開発中に同じ問題が発生しました。また、コードを可能な限り最適化しようとしましたが、うまくいきませんでした。次に、それらのpngのサイズを小さくしてみました。ドローアブルリソースのサイズ(存在する場合)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.