web-dev-qa-db-ja.com

バックグラウンドスレッドでビューを膨らませる

私は非常に簡単な質問をします:

バックグラウンドスレッド(例:doInBackground)でビューを(レイアウトに追加しないで)ビューをインフレートできるかどうかAsyncTask)の?

Galaxy S: Android:Android.view.InflateException:Binary XML file lineでこの問題が発生するまで、ほとんどのアクティビティをこの方法でアプリケーションに実装し、問題は発生しなかったので、それが可能であることを知っています。 #13:SAMSUNG Galaxy Sのクラス<unknown>のインフレート中にエラーが発生しました

私はバックグラウンドスレッドでViewsを膨らませないべきですと言われましたが、具体的な理由は何ですか?なぜ私のアプローチはほとんどのデバイスでは機能しませんがGalaxy S?

35
pandre

LayoutInflaterは、どのスレッドで実行されているかについては何も想定していません。そして、そのドキュメントではこれについて何も言及されていません。また、そのコードはスレッドにとらわれないように継ぎ合わせています。

一方、LayoutInflaterによって作成されたビューは、コンストラクターでHandlersをインスタンス化する場合があります。まあ、おそらくそうすべきではありませんが、コンストラクターでHandlersを作成/使用しないという要件はありません。

私の推測では、Samsung Galaxy SのEditTextにいくつかの変更が加えられ、何らかの形でHandlerの作成がトリガーされたと思われます(GestureDetectorの他の質問インスタンスからのクラッシュログによると、新しいHandler)を作成します。デフォルトの実装はこれを行いませんが。


全体として、コンストラクターでViewsおよびHandlersを使用しないというLoopersの明示的な要件がないため、非UIからのビューの拡張を想定できないと思いますスレッドは安全です。

実際に HandlerThread を作成し、その内部でViewsを膨らませることができます。ただし、Samsung Galaxy Sの例のように、ビューはこのスレッドがViewの存続期間中は有効であり、Looperを使用してすべてのメッセージを処理すると想定しているため、これは非常に危険だと思います。後でクラッシュする可能性があります。

40
inazaruk

最新のサポートライブラリを使用すると、 Android.support.v4.view.AsyncLayoutInflater 非同期にビューを拡張します。ただし、特定の要件が満たされていない場合は、UIスレッドの拡張にフォールバックする可能性があるので注意してください。

レイアウトを非同期的に膨張させるには、generateLayoutParams(AttributeSet)がスレッドセーフである親が必要であり、インフレーションの一部として構築されるすべてのビューは、ハンドラーを作成したり、myLooper()を呼び出したりしてはなりません。何らかの理由でインフレートしようとしているレイアウトを非同期で構築できない場合、AsyncLayoutInflaterは自動的にUIスレッドのインフレーションにフォールバックします。

14
M-WaJeEh

バックグラウンドスレッド(例:AsyncTaskのdoInBackground内)でビューを膨張させる(レイアウトに追加しない)ことは可能ですか、それとも不可能ですか?

はい、可能です。おすすめですか?いいえ。ドキュメントに記載されているとおり:

したがって、Androidのシングルスレッドモデルには2つのルールがあります。

  1. UIスレッドをブロックしない
  2. Android UIツールキットにはUIスレッドの外部からアクセスしないでください

経由: プロセスとスレッド

更新[02/06/19]:

どうやら、サポートライブラリにはこれを行うツールがあります: AsyncLayoutInflaterJetpack version )。バージョン24、2016年頃に導入されました(私の回答から2年後)

ただし、他の回答で述べたように、このツールは非常に簡単に裏目に出る可能性があるため、注意が必要です。

4
pablisco