Android

Android開発Fragmentについてのまとめ

投稿日:2017年4月24日 更新日:

Android開発のFragmentについての注意事項をまめました。いくつかの守るべきルールや既に確立されたコーディングスタイルがあるようです。それを守らないとある程度は動いているんだけど、動作をさせていたらあるタイミングで落ちてしまうという事になるようです(WEBページのコピペでも動作するけで、回転させると落ちてしまった・・・・ような経験は何度もしてきました)。なるべく同じようなミスをしないように今までハマった点をまとめてみました。

 

静的な方法、動的な方法

FragmentのActivityへの組み込みは、XMLレイアウトの<fragment>を用いる静的な方法と、FragmentTransactionを用いる動的な方法があります。

(静的な方法)

fragmentのandroid:nameは上で作成したFragmentクラスのクラス名です。フラグメントの生成管理をシステム側で行うので、以下の動的なコードを記述する必要がありません。

(動的な方法)

上記はActivityにFragmentを貼付けるケースです。ポイントはsavedInstanceState==nullの時のみ、R.id.mainの部分にFragmentを貼付ける(=replaceする)処理を行う事です。Fragmentの貼付け/張り替えはFragmentManager経由で行います。savedInstanceState==nullのif文がない場合は、回転した都度、新しいフラグメントが生成される事になります。

 

値の引き渡しについて

(1)呼出し元のActivity(Fragment)から呼出し先のFramentへの値の引き渡し

NewInstanceメソッドの引数で引き渡します。NewInstanceメソッド内では、setArguments()でバンドルに格納するようにします。Fragment のコンストラクタで引数を渡すのはダメです。Fragmentを継承したクラスは空のコンストラクタを用意する必要があるためです。Fragmentの再生成の時に空のコンストラクタがシステムからコールされます。

(2)呼出し先のFramentから呼出し元のActivity(Fragment)への値の引き渡し

(方法1)
コールバックリスナーを使用する方法です。しかし、回転やプロセス管理による再生成処理で、登録したリスナーが初期化されるので(nullになるので)、onAtttachイベントでリスナーを復活する(呼出し元との紐付けを再度行う)必要があります。呼出し元がActivityの場合はonAtttachの引数がActivityなので、そのままリスナーのインターフェースでキャストすれば問題ありませんが、呼出し元がFragmentの場合は、setTargetFragmentで設定したフラグメントをgetTargeFramentで呼び出して、リスナーのインターフェースでキャストする必要があります。setTargetFragment()メソッドで呼び出し元Fragmentをセットしており、ここでセットされた呼び出し元FragmentオブジェクトはgetTargetFragmentで取り出せます。getTargetFragmentで取り出したFragmentは、Activity/Fragment再生成時に関係の整合性を保持した状態のFragmentになっています。

 

(方法2)
Intentに結果を詰めて呼び出し元のonActivityResult()を直接呼ぶ方法です。呼び出し元はonActivityResult()で結果を処理します。

setTargetFragment()メソッドで呼び出し元Fragmentとリクエストコードをセットしています。ここでセットされた呼び出し元Fragmentオブジェクトは、Activity/Fragment再生成時に関係の整合性を保持したままセットされるというものです。よって、getTargetFragmentで取り出したFragmentは、再生成時に関係の整合性を保持した状態のFragmentになっています。

 

入れ子(ネストする)のFragment

ネストするフラグメントを使用する時は、getChildFragmentManager()を使用します。

 

getActivity()でnullが返ってくる場合

getActivity()とは、現在Fragmentと関連付けられているActivityを返すメソッドになります。回転などによるconfigChangeの発生やメモリ圧迫等によるシステムからの破棄によって、Activityの再生成が発生した場合、通常であればシステム側が自動で関連付けを行うためnullが返ってくる事はないが、AsyncTaskの非同期タスク実行中に回転などが発生した場合、非同期タスク完了後のコールバック処理のリスナー側処理でnullになる場合がある。

(例)AsyncTaskの処理完了後のコールバックリスナーの処理でgetActivity()を実行した場合。AsyncTaskに対応するActivityは既に破棄されている。AsyncTaskLoaderを使って対応する。

 

再生成処理

Activity/Fragmentの再生成には二つのパターンがあります。

1.メモリ圧迫等によるシステムのprocess killによる破棄からの再生成
2.回転などのconfigChangeでの再生成

 

onAttach

Fragmentで用意されているonAttach(Activity)メソッドは、一度fragmentで呼び出されると、Activityと関連付きます。API 23以前は、以下のように利用していました。

上記のコードは、FragmentからActivityにコールバックする必要がある場合の処理です。Fragmentはメモリが不足すると、システムによって破棄され、必要な時に再生成されます。すると、コールバックが受け取れなってしまう場合があります。API 23でonAttach(Activity)メソッドは、deprecatedになりました。代わりにonAttach(Context)   を使います。新たに追加されたonAttach(Context)メソッドは、API 23(Android6.0)からの利用となります。なので、以前のandroidにも対応する場合は、両方のメソッドを呼び出す必要があります。

 

よく使うFragment関連のメソッド

getFragmentManager().findFragmentByTag(TagName); Fragmentのインスタンスを取得する

List<Fragment> list = getFragmentManager().getFragments(); 現在保持しているFragmentをListで返す 

 

setArguments()を初期化以外で使用すると問題がある

setArguments() を初期化以外で使用すると、「java.lang.IllegalStateException: Fragment already active and state has been saved」が発生する。

状態保存には onSaveInstanceState を使用する

参考にした資料:【Android 実装の罠 #1】 Fragment#setArguments()

 

onSaveInstanceStateがコールされない場合がある

  • OnSaveInstanceStateリスナでは呼ばれない場合があるため、onPauseを使用して、 getArgumentsで取得したバンドルに保存する。
  •  画面の回転においては、OnSaveInstanceStateが正常にコールされるが、フラグメントをreplaceした時に別フラグメントの表示でOnSaveInstanceStateがコールされないため、バックスタックからの復活した再作成で値の保存・復活が出来ない。
  • onPauseでBundleリスナーの発生は、OnSaveInstanceStateを包含するため、値の保存処理はonPauseで処理する。setArguments()は実行しないこと。

 

スポンサーリンク

スポンサーリンク

-Android

執筆者:

関連記事

Activityの復元について

  参考ページ 【Android】savedInstanceStateの意味と開発者オプション【初心者向け】 Android の罠 [1] ちゃんと onSaveInstanceState ...

Android開発のリストビューに関するTIPS

android開発のリストビューに関するTIPSをまとめました。   ListViewの使い方 業務アプリによるListViewの使い方のポイント 基本的に表示するだけの一覧表示するだけの機 ...

Android StudioのTIPS

Android StudioのTIPSをまとめました。   Android Studioで解決できないコンパイルエラーが発生した時の対応 今まで問題がなかったプロジェクトが、急にコンパイルエ ...

Android開発TIPS

android開発TIPSをまとめました。   androidのswitch文で「定数式が必要です」エラーが発生する対応 android開発で、switchのcase文にR.idを入れたらエ ...

Android開発のTIPS WEBページ 

  スレッドから画面操作 スレッドからUIを操作する編集する Android 非同期処理についてまとめてみた 別スレッドでキュー管理(Handler, Looper, HandlerThre ...