31
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

FragmentManager#executePendingTransactions() が怖くて使えないあなたへ

Last updated at Posted at 2014-04-03

Fragmentを取り扱っていると必ず出てくるのが、FragmentManagerFragmentTransactionです。

FragmentManagerは、1 個のActivity につき 1 個のFragmentManagerが居て、Activityのライフサイクルの巡りが尽きて死ぬまでの間、そのActivityでのFragmentのライフサイクル管理をしてくれます。

Fragmentの取り扱い方としては、レイアウトに埋め込んで静的に動作させるやり方と、Activityが動的にFragmentのインスタンスを生成してレイアウトにアタッチするやり方があり、特に後者の動的にアタッチするやり方を採用した時に、FragmentTransactionを用いてFragmentのレイアウトに対する各種の操作を実行します。

さて、FragmentTransactionを使って動的にアタッチしようとすると、たまに以下の様な事象に出くわすことが有ります。

イベントのコールバック中に FragmentManager#findFragmentByTag() でアタッチした Fragment を取得しようとしたら、 FragmentTransaction#commit() したはずなのに null が返ってきた

FragmentTransaction#commit()が、即座にFragmentをレイアウトに反映するわけではない、ということは、Android Developers にも記載があります。

Schedules a commit of this transaction. The commit does not happen immediately; it will be scheduled as work on the main thread to be done the next time that thread is ready.

トランザクションのコミットをスケジューリングするよ、ということなので、commit()メソッドが同期的にFragmentをアタッチするわけではない、というわけです。もう少し掘り下げると、できるだけ早く、メインスレッドが有効になってから、commit()された内容を実行できるように、Handlerにメッセージを投げてスケジューリングする、という事になります。

このような状況の回避策としてあげられるのが、FragmentManager#executePendingTransactions()です。

このメソッドの実体はこのあたりにあります。

ざっくりとまとめると、FragmentTransaction#commit()によってキューに積まれたジョブを同期的に実行し、Fragmentのアタッチ等をその場で実行してくれる、ということをします。

ということは、メインスレッドが有効になってからできるだけ早く実行されるとはいえ、メッセージキューに積まれたメッセージの数に依存して、実際の実行されるタイミングのスケジュールが決まるということになります。

つまり、FragmentTransactionによるメッセージ以外に何らかのメッセージがたまった状態だと、FragmentTransactionによる操作が実行される前に他のメッセージが処理される事になり、そのメッセージの中でFragmentManager#findFragmentByTag()等をすると、まだFragmentがアタッチされていないのでnullが返る、ということになります。

ありがちなのは、非同期処理のコールバックでプログラスを表示するFragmentを非表示にしようとしたとき、プログレスを表示するFragmentがアタッチされるよりも前に非同期処理が終わってしまい、先にメッセージキューに積まれてしまう、という状況です。
そのような状況にならないよう、FragmentManager#executePendingTransactions()を使って、先にFragmentをアタッチしてから非同期処理を開始するように強制する、ということです。

もちろん、Fragmentをアタッチする操作が先になるよう強制されるので、アタッチされたことを受けて何らかの振る舞いをするような場合には、注意が必要です。これはドキュメントにも記載されています。

Note that all callbacks and other related behavior will be done from within this call, so be careful about where this is called from.

もう、これでFragmentManager#executePendingTransactions()は怖くない!

31
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?