Android Developersのフラグメントを訳しました。
Android3.0と共にやってきたFragmentはActivityを複数に分割して、タブレットでは大画面に多数の情報を表示して、スマートフォンでは情報を分けて表示できたりするクールな奴
そして、それだけじゃなく、パーツを部品化出来ることでプログラムがシンプルになることも期待できるみたい
最近は英語の勉強を兼ねてAndroid Developersの翻訳をやっているけれど、最初は翻訳サイト頼みだったのがだいぶ辞書で単語の意味を調べるだけで翻訳できるようになってきました。
達成感があってとっても楽しいです。
原文
Fragment
FragmentはActivityの振る舞いやUIの一部を表現します。マルチペインユーザーインターフェイスを構築するために一つのActivityに複数のFragmentを組み込めます。そして複数のActivityでFragumentを再利用できます。
FragmentはActivityのモジュールセクションとして考えることが出来ます。
それはライフサイクルを持ち、インプットイベントを受信し、Activityが実行中に追加したり、削除することが出来ます。
Fragmentは常にActivityに埋めこまれている必要があります。
ライフサイクルはホストActivityのライフサイクルの影響を直接受けます。
例えばActivityがpausedされたとき、その中にある全てのFragmentも同様にpausedされます。
Activityが破棄されるとき、Fragmentも同様に破棄されます。
しかし、Activityが実行される間(ライフサイクルはresumed状態)追加したり、削除するなどFragmentを独立して操作することが出来ます。
フラグメントトランザクションを実行する時、Activityが管理するバックスタックにそれを追加できます。
Activityの各バックスタックエントリーはフラグメントトランザクションの発生した記録となります。
バックスタックはユーザーが戻るボタンを押すことでFragmentのトランザクションを戻せる(逆方向の操作)ようにします。
Activityのレイアウトファイル内でFragmentエレメントを宣言するか、アプリケーションコードで既存のViewGroupに加えることでActivityレイアウトにFlagmentを挿入できます。
しかし、FragmentはActivityレイアウトの一部である必要はありません。FragmentをActivityの非表示ワーカーとして使うことも出来ます。
このドキュメントは、FragmentがActivityのバックスタックに加えられるとき、どうやってFragmentがその状態を保存するか、Activityとその他のFragmentでイベントを共有すること、アクションバーを活用する方法、その他Fragmentを使ったAplicationの構築方法を説明します。
デザイン哲学
主に、大きなスクリーンでよりダイナミックで柔軟なユーザーインターフェイスデザインをサポートするために、AndroidはAndroid3.0(API Level "Honeycomb")でFragmentを追加しました。なぜなら、タブレットの画面は携帯電話よりとても大きいので、UIの構成要素を入れ替える多くの余地があるからです。
FragmentはView階層の複雑な変更を管理する必要なく、そのようなデザインが使用できます。
ActivityのレイアウトをFragmentに分けることによって、実行時にActivityの表示を変えたりActivityが管理するバックスタックに変化を保存できるようになります。
例えば、ニュースアプリケーションは一つのActivityで左に記事リストを表示させたfragment、右に記事の内容を表示させた別のfragment、両方のFragmentを並んで表示させることができます。
そして、それぞれのFragmentはそれ自身が自分のライフサイクルコールバックメソッドと入力イベントを取り扱います。
こうして、記事を選ぶActivityと記事を読むActivityを使う代わりに 図1のように一つのActivity内で記事を選び、読むことが出来ます。

図1 典型的な二つのActivityに分かれた二つのユーザーインターフェイス部品を、Fragmentを使って一つのActivityにまとめた例
フラグメントはアプリケーション内でモジュール化されで再利用出来るコンポーネントです。
つまり、Fragmentは自分のライフサイクルコールバックを使って自身のレイアウトと振る舞いを確立しているので、複数の異なるActivityで同じFragmentを使う事が出来ます。
異なるスクリーンサイズでユーザーエクスペリエンスを適合させるためにこれは特に重要です。
例えば、十分に大きなディスプレイの場合のみ複数のFragmentを一つのActivityに含め、そうでないときは異なるFragumentごとに異なるActivityを開始します。
ニュースの例で言うと、タブレットなどの大きなディスプレイで動かすとき、2つのFragumentをActivity Aに含めることが出来ます。
しかし、電話など普通サイズのディスプレイには両方のFragmentを含める空間がありません。
そのため、Activity Aには記事のリストFragmentだけを含めて、ユーザーが記事を選択したとき、記事を表示するFragmentを含めたActivity Bを開始します。
このようにアプリケーションは図1で示す両方のデザインパターンをサポートします。
Fragmentを作る
Fragmentを作るにはFragment(または既存のFragmentのサブクラス)のサブクラスを作ります。FragmentのコードはActivityにとても似ています。
onCreate(),onStart(),onPause()そしてonStop()などActivityと同じコールバックメソッドを持ちます。
実のところ既存のアプリケーションからFragmentを使うように移行したいならば、単にFragmentのそれぞれのコールバックメソッドにActivityのコールバックメソッドのコードを移動するだけでいいかもしれません。
通常、以下のライフサイクルを実装する必要があります。
onCreate()
Fragmentを作成したとき、システムから呼ばれます。
pausedまたはstoppedから再開する時に必要なFragmentのコンポーネントを初期化します。
onCreateView()
Fragmentのユーザーインターフェイスが最初に描画されるときシステムから呼ばれます。
Fragmentのユーザーインターフェイスを描画するために、このメソッドはFragmentLayoutのルートViewを返す必要があります。
UIを持たないFragmentの場合Nullを返すことが出来ます。
onPause()
ユーザーがFragmentから離れようとしている場合、(Frƒagmentが破棄されるとは限りません)システムは最初にこのメソッドを呼びます。
通常、ユーザーセッションを越えるあらゆる変化を確定させる必要があります。(ユーザーがもどってこないことがあるため)
Fragmentのためには、ほとんどのアプリケーションは少なくとも上記3つのメソッドを実装する必要があります。
しかし、Fragmentの様々なライフサイクルを扱うためには他にも使用しなければならないコールバックメソッドがあります。
Fragmentのライフサイクルをハンドリングするの章で全てのライフサイクルのコールバックメソッドを解説しています。
基本的なFragmentクラスの代わりに継承した方が良い可能性があるサブクラスがあります。
DialogFragment
フローティングダイアログを表示します。ActivityクラスのDialogヘルパーメソッドを置き換えるものです。
なぜなら、Activityが管理するFragmentのバックスタックに組み込むことが出来て、ユーザーが除外されたFragmentに戻ることを許可するためです。
ListFragment
アダプタ(SimpleCursorAdapter等)で管理されるアイテムのリストを表示します。ListActivityに似ています。
リストビューを管理するために、クリックイベントをハンドリングするコールバックonListItemClickなどのメソッドを提供します。
PreferenceFragment
Preferenceオブジェクトリストの階層を表示します。PreferenceActivityに似ています。
これは設定Activityを作成する際に使用します。

図2 フラグメントのライフサイクル(Activity実行中)
ユーザーインターフェイスの追加
Fragmentは大抵Activityのレイアウトに影響しユーザーインターフェイスの一部となります。Fragmentにレイアウトを提供するためにonCreateView()コールバックメソッドを実装する必要があります。
それはFragmentのレイアウトを描画するときにAndroidシステムより呼ばれます。実装したメソッドはFragmentレイアウトのルートViewを返す必要があります。
ノート;もし、ListFragmentを継承した場合、標準でonCreateView()がListViewを戻します。
そのため、あなたはそれを実装する必要がありません。
onCreateView()でレイアウトを返すために、XMLに記載したレイアウトリソースをインフレートすることが出来ます。
それを手助けするためにonCreateView()はLayoutInflaterオブジェクトを提供します。
例えばこれはFragmentを継承したクラスがexample_fragment.xmlファイルからレイアウトを読み込んでいます。
public static class ExampleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
}
onCreateView()に渡されるcontainerパラメータは(ActivityLayoutによる)親のViewGroupです。Fragmentのレイアウトはこれに入ります。
savedInstanceStateパラメータはFragmentが再開するときに前回のFragmentのデータを提供するバンドルです。
(状態の復帰はFragmentのライフサイクルをハンドリングするの章で議論されます)
inflate()メソッドは3つの引数を取ります。
インフレートさせたいレイアウトリソースのレイアウトID
インフレートレイアウトの親ViewGroups。システムがインフレートされたレイアウトの(親として指定される)ルートviewにレイアウトパラメータを適用するためにcontainerを渡すことが重要です。
インフレートレイアウトがインフレート中に(2番目のパラメータで指定した)viewGroupに付いている必要があるかどうかを表すブーリアン。(このケースではこれはFalseです。なぜならシステムは既にインフレートされたレイアウトをコンテナに入れているので、)
ここまで、レイアウトを提供するFragmentをどうやって作るかを説明しました。次はActivityにFragmentを追加するのに必要なことを説明します。
ActivityにFragmentを追加する。
Fragmentは通常ホストActivityのUIの一部を提供します。そしてそれはActivityのView階層全体一部として組み込まれます。ActivityレイアウトにFragmentを追加する2つの方法があります。Activityのレイアウトファイル内にFragmentを宣言する
この場合ビューのようにFragmentのレイアウトプロパティを指定することが出来ます。例えば1つのActivityに2つのFragmentを記載するレイアウトファイルは次のとおりです。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.news.ArticleListFragment"
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.news.ArticleReaderFragment"
android:id="@+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
fragmentのandroid:name要素にlayoutに実装するFragmentのクラスを記載します。
システムがこのActivityレイアウトを作るとき、レイアウトで指定されたFragmentをインスタンス化し、それぞれのレイアウトを取得するためにonCreateView()メソッドを呼びます。
システムFragmentが返したViewを直接Elementの場所に挿入します。
ノート Activityが再開されたとき、Fragmentをリストア出来るようにそれぞれのFragmentはユニークなIDが必要です。(このIDはFragmentを削除するるなどのトランザクションを行うときにFragmentを取得するのに使用できます。)FragmentのためにIDを振り分ける3つの方法があります。
・android:id属性に一意のIDを付与する
・android:tag属性に一意の文字列を付与する。
・もしあなたが上記二つのどちらも付与しない場合、システムはcontainerビューのIDを使用する。
または、既存のViewGroupにプログラムでFragmentを追加する。
Activityが実行中、いつでもactivityレイアウトにFragmentを加えることが出来ます。単にFragmentを置くViewGroupを指定する必要があるだけです。
フラグメントに関する一連の作業(フラグメントを追加したり、削除したり、置き換えるなど)を行うにはFragmentTransactionが提供するAPIを使用する必要があります。
下記の方法でActivityよりFragmentTransactionのインスタンスを取得できます。
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragmentを加えるにはadd (int, Fragment)メソッドを使用します。追加するFragmentと追加されるViewGroupを指定します。例:
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
最初の引数はFragmentが追加されるViewGroupのリソースIDです。次のIDは追加するFragmentです。
FragmentTransactionで変更作業を行った場合、エフェクトの変化のためにcommit()メソッドをコールする必要があります。
ユーザーインターフェイスを持たないFragmentの追加
上記ではユーザーインターフェイスを提供するためにFragmentをActivityに加える方法を示しました。しかし、バックグラウンドでの挙動をActivityに提供するためにユーザーインターフェイスを表示すること無いFragmentを使うことも出来ます。
Activityへユーザーインターフェイスを含まないFragmentを加えるにはadd(Fragment, String)(intのViewIDではなくstringのtagを使用します)。これでFragmentを追加できます。ActivityのViewと結びついていないため、onCreateView()は呼ばれません。そのためこのメソッドを実装する必要はありません。
厳密には文字列のタグはユーザーインターフェイスを含まないFragmentのためだけにあるわけではありません。ユーザーインターフェイスを持つFragmentでも文字列のタグを渡すことが出来ます。しかし、Fragmentにユーザーインターフェイスがない場合、文字列のタグはFragmentを確認する唯一の方法です。
後でActivityからFragmentを取得するには、findFragmentByTag(String tag)を使用する必要があります。
ユーザーインターフェイスのないFragmentをActivityのバックワーカーとして使う例はFragmentRetainInstance.javaを見てください。
Fragmentの管理
Activity内のFragmentを管理するにはFragmentManagerを使用する必要があります。ActivityからgetFragmentManager()をコールしてください。FragmentManagerでは以下のことが出来ます。
- findFragmentById(int id) (Activityにユーザーインターフェイスを提供するFragment)または findFragmentByTag(String tag) (ユーザーインターフェイスを持たないFragment)でActivityに入っている既存のFragmentを取得する。
- popBackStack()でバックスタックからFragmentを取り出す(ユーザーのバックキーをシミュレートする)
- addOnBackStackChangedListener(FragmentManager.OnBackStackChangedListener listener)でバックスタックの変更リスナーを登録する。
より多くの情報はFragmentManagerクラスのドキュメントを参照してください。
前章で述べたように、Fragmentを追加したり削除するトランザクションのためにFragmentManagerでFragmentTransactionを開くことが出来ます。
FragmentTransactionの演出
Activity内でFragmentを使う素晴らしい特徴は、ユーザーのインタラクションに応じてFragmentの追加・削除・置き換え・その他アクションが行えるようになることです。
FragmentTransactionのAPIによる、Activityにコミットされる変化の各セットはトランザクションと呼ばれます。また、Activityが管理するバックスタックへ各トランザクションを保存することが出来、ユーザーがFragmentの変化を戻すことが出来ます。(Activityを戻るときに似ています)
FragmentManagerによるFragmentTransactionを取得するには以下のようにします。
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
各トランザクションは同時に変更を行いたい一組の操作です。
add(),remove()そしてreplace()などのメソッドでどのような変化を行いたいかトランザクションにセットします。
そして、Activityに各トランザクションを適用するためにcommit()をコールします。
また、commit()をコールする前に、addToBackStack()をコールした方がいい時もあります。
このバックスタックはActivityに管理され、そしてユーザーが戻るボタンを押したときに以前のFragmentの状態に戻ることを許します。
これは一つのFragmentを他のFragmentと入れ替え、以前の状態をバックスタックに保存する例です。
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
この例では、newFragmentが(もしあるなら)現在R.id.fragment_container IDにより特定されるレイアウトコンテナのFragmentと置き換わります。
addToBackStack()を呼ぶことで、置き換えるTransactionをバックスタックに保存することが出来て、ユーザーは戻るボタンを押すことで、トランザクションを巻き戻し、以前のFragmentに戻すことが出来ます。
もし、他のadd()やremove()など複数の変更をトランザクションに追加し、addToBackStack()を読んだら、全てのcommit()以前の状態が一つのトランザクションとしてバックスタックに追加され、戻るボタンにより全てが同時に戻ります。
変更をFragmentTransactionに追加する処理で重要なのは次のことだけです。
- 最後にcommit()を呼ぶ必要がある。
- もし、複数のFragmentを同じコンテナに追加したら、追加する順番でView階層を決定します。
もしFragmentを削除するトランザクション時にaddToBackStack()を呼ばなかったら、トランザクションがコミットされるときにFragmentは破棄されます。そしてユーザーは戻ることが出来ません。addToBackStack()を呼んでいたら、Fragmentはstopされます。そしてユーザーが戻るときresumeされます。
チップ 各フラグメントのトランザクションをアニメーションさせるにはsetTransition()をコミットの前に呼ぶ
commit()が呼ばれても即時にTransactionが実行されるわけではありません。
スレッドが実行可能になるまでActivityのUIスレッド(メインスレッド)にスケジュールされます。しかし、executePendingTransactions()をUIスレッドから呼ぶことでcommit()の処理を即座に反映させることができます。これは普通、他のスレッドのジョブに依存するようなことがない限り必要ありません。
警告:commit()でトランザクションをコミットできるのは、(ユーザーがActivityから離れ)状態を保存する前までです。もしそれ以降にcommitを試みると例外がスローされます。これはActivityの復元時にコミットより後の状態が失われてしまうおそれがあるためです。コミットする内容が失われてもいい場合はcommitAllowingStateLoss ( ) を使用します。
Activityとのやり取り
FragmentはActivityから独立し、複数のActivityに含めることすらできるが、実際のところ、そのインスタンスはそれが含まれるActivityと連携します。具体的には、FragmentはActivityのインスタンスへgetActivity()を使ってアクセスできます。そして簡単に下記のActivityレイアウトのViewをさがす例のように行うことができます。
View listView = getActivity().findViewById(R.id.list);
同様に、ActivityからFragmentManagerのfindFragmentByIdかfindFragmentByTagを使ってFragmentの参照を取得し、Fragmentのメソッドを呼び出せます。その例です。
ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
Activityへのイベントコールバックの作成
ActivityとFragmentでイベントを共有する必要がある時もあります。そのためにはFragmentでcallbackインターフェイスを宣言して、ホストのActivityでそれを実装させると良いです。そのとき、インターフェイスを介してActivityが受け取るコールバックによりレイアウトに内包する他のFragmentと必要な情報を共有することが出来ます。例えば、もし、一つのActivityで記事一覧を表示するFragment Aと記事を表示するFragment B の2つのFragmentを持つニュースアプリケーションの場合、Fragment Aは記事が選択されたときActivityにそれを伝える必要があります。そうすることでFragmentBに記事を表示するように伝えることが出来ます。このケースでは、OnArticleSelectedListenerインターフェイスをFragmentAの中で宣言しています。
public static class FragmentA extends ListFragment {
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
...
}
そのFragmentをホストする、ActivityがOnArticleSelectedListener()インターフェイスを実装し、onArticleSelected()をオーバーライドすることでfragmentAのイベントをfragmentBに通知します。ホストのActivityがインターフェイスを実装するのを確実にするためにFragment AのonAttach()コールバックメソッド(システムがActivityにFragmentを追加するときにコールされます)で引数として渡されたActivityをOnArticleSelectedListenerにキャストし、インスタンスとする具体例を示します。
public static class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
...
}
もし、Activityがインターフェイスを実装しなかったら、FragmentはClassCastExceptionをスローします。成功したらOnArticleSelectedListenerを実装するActivityへの参照をmListenerメンバ変数が取得し、Fragment AはOnArticleSelectedListenerインターフェイスによって宣言されたメソッドを呼び出すことでイベントをActivityと共有出来ます。例えば、もしFragment AがListFragmentを継承していると、ユーザーがクリックする度にFragmentのonListItemClick()メソッドがシステムから呼ばれ、そのなかでonArticleSelected()を呼ぶことでActivityとイベントを共有します。
public static class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
...
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Append the clicked item's row ID with the content provider Uri
Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
// Send the event and Uri to the host activity
mListener.onArticleSelected(noteUri);
}
...
}
onListItemClick()の引数IDはクリックされたアイテムの行IDです。Activity(または他のFragment)はアプリケーションのContentProvider.を使用して記事を探し出します。
より詳細な役立つ情報はContent Providersドキュメントにあります。
ActionBarにアイテムを追加する。
FragmentはonCreateOptionMenu()を実装することでActivityのオプションメニュー(そして結果としてアクションバーにも)メニューアイテムを提供します。このメソッドが呼ばれるようにするにはonCreate()内でsetHasOptionsMenu()を呼び出し、Fragmentはオプションメニューにアイテムを追加したいことを明示する必要があります。(それをしないとFragmentは onCreateOptionsMenu()を受け取りません。)オプションメニューの既存のメニューアイテムへFragmentによる全てのアイテムが追加されます。メニューアイテムが選択されるとFragmentは同様に onOptionsItemSelected()コールバックを受信します。
registerForContextMenu()を呼び出すことでコンテキストメニューにFragmentレイアウトのviewを登録できます。それによりユーザーがコンテキストメニューを開くとonCreateContextMenu()が呼び出され、ユーザーがアイテムを選択するとFragmentはonContextItemSelected()を受信します。
ノート:Fragmentは各追加されたメニューアイテムからアイテムが選択されたコールバックを受けるが、ユーザーがメニューアイテムを選択したときにそれぞれのコールバックを最初に受けるのはActivityです。
もしActivityによるon-item-selectedコールバックの実装が選択されたアイテムをハンドルしないならば、イベントはFragmentのコールバックに渡されます。これはオプションメニューとコンテキストメニューにおける事実です。
メニューに関するより詳しい情報はCreatingMenusとUsing the Action Barを見てください。
Fragmentのライフサイクルをハンドリングする
Fragmentライフサイクルの管理は、Activityのライフサイクル管理と似ています。Activityに似てFragmentは3つの状態を持つことが出来ます。Resumed
Fragmentは実行中のActivity上で表示されます。
Paused
他のActivityが全面で動きフォーカスされています。しかし、Fragmentと、Fragmentを含むActivityは生きておりまだ表示されています。(全面のAcitivityは部分的に半透明であるか、スクリーン全体を覆ってはいません)
Stopped
Fragmentは表示されていません。ホストのActivityがStoppedしているか、FragmentがActivityから取り除かれているがバックスタックに加えれられています。Stopped Fragmentはまだ生きています。(すべての状態とメンバーの情報はシステムが持っています)しかしながら長い間非表示であったり、Activityがkillされるとkillされます。
ActivityのプロセスがKillされた後、Activityを再開する際にFragmentの状態を復元する必要がある場合、Activityと同様にあなたはBundleを使って状態を持ち続けることが出来ます
Fragmentの onSaveInstanceState()コールバック内で状態を保存し、onCreate(), onCreateView()あるいは onActivityCreated()で復元します。
状態を保存するより詳細な情報はActivitiesドキュメントを見てください。
ActivityとFragmentのライフサイクルにおける興味深い違いは、バックスタックにどのように保存されるかです。Activityは標準でStoppedされたときシステムによりActivityのバックスタックに置かれます。(それによりユーザーは戻るボタンで前に戻ることができます。それについてはTasks and Back Stackに記載されています)しかし、Fragmentは削除されるときにaddToBackStack()を呼び、インスタンスを保存することを明示したときのみ、ホストが管理するActivityのバックスタックに置かれます。
他の点ではFragmentライフサイクルの管理はActivityのライフサイクルの管理にとても似ています。そのため、managing the activity lifecycleと同じ方法でFragmentも行うことができます。
しかし、Activityのライフサイクルがフラグメントのライフサイクルにどのように影響を及ぼすかは理解する必要があります。
Activityライフサイクルとの調和
Activityが各ライフサイクルのコールバックを受けるとFragmentのコールバックも同様になるように、ActivityのライフサイクルはFragmentのライフサイクルへ直接影響します。例えばActivityがonPause()を受信するとアクティビティ内の各FragmentはonPauser()を受信します。Fragmentは多少追加のライフサイクルコールバックを持っていますが、これはActivityがFragmentのUIを構築、破棄する時にActivityとの独自の相互作用をハンドルします。次は加えられるコールバックメソッドです。
onAttach()
FragmentがActivityに結びつくときに呼ばれます。(Activityが引数として渡されます)
onCreateView()
Fragmentと結びつくView階層を作るために呼ばれます
onActiveCreated()
ActivityのonCreate()メソッドからもどってきたときに呼ばれます。
onDestroyView()
Fragmentに結びつくView階層が削除されるとき呼ばれます。
onDetach()
ActivityからFragmentが切り離されるときに呼ばれます。

図3ActivityライフサイクルがFragmentLifecycleに与える影響
ホストActivityに影響されるFragmentライフサイクルの流れを描いたのが図3です。この図はActivityの状態変化によりFragmentのどのメソッドが呼ばれることがあるかを見ることが出来ます。例えばActivityがonCreate()コールバックを受け取ったら、Activity内のFragmentはonActivityCreated()コールバックまで呼ばれます。
一度Activityがresumed状態になると、あなたは自由にFragmentをActivityから追加したり削除したり出来ます。それゆえ、Activityのresume状態は独立してFragmentのライフサイクルを変更できる唯一の状態です。
しかし、Activityがresume状態から離れると、FragmentはまたActivityのライフサイクルにより呼び出されます。
例
ドキュメントで議論した内容をまとめます。これは1つのActivityが2ペインレイアウトを作るために2つのFragmentを使用する例です。Activityは下のシェイクスピアの演劇タイトルリストを表示するFragmentとリストで選択された演劇の概要を表示する物を含みます。それはスクリーンの設定により、異なるFragmentの設定を提供する方法も含みます。ノート Activityのための完全なソースコードはFragmentLayout.javaに含まれます。
通常通りにActivityはonCreate()でレイアウトを適用します。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_layout);
}
レイアウトはfragment_layout.xmlを適用します。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
android:id="@+id/titles" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />
<FrameLayout android:id="@+id/details" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent"
android:background="?android:attr/detailsElementBackground" />
</LinearLayout>
このレイアウトを使用してActivityがレイアウトを呼ぶとシステムはTitleFragment(演劇のタイトルリスト)をインスタンス化し、FrameLayout(演劇の概要を表示することになる)はスクリーンの右側の空間を空のままで埋める。ユーザーがアイテムを選択するとFrameLayoutの位置にFragmentを置くことになる。
しかし、全てのスクリーン構成がタイトルのリストと記事を並べて表示するのに足りるわけではありません。そのため res/layout-land/fragment_layout.xmlとして保存しディスプレイが横向きの時だけ反映されるようにします。
そのため縦向きの画面でシステムが使用するレイアウトをres/layout/fragment_layout.xml:として保存します。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
android:id="@+id/titles"
android:layout_width="match_parent" android:layout_height="match_parent" />
</FrameLayout>
このレイアウトはTitleFragmentのみをふくんでいます。これにより、デバイスが縦向きの時は演劇のタイトルのみが表示されます。そのため、この設定でユーザーがリストをクリックした場合は、アプリケーションは2つ目のFragmentを呼ぶ代わりに新しいActivityを開始して概要を表示します。
次に、Fragmentクラスがどうやってこれを行うかについて見ていきます。まず最初はシェイクスピアの演劇タイトルを表示するTitleFragment、これはListFragmentを継承し、list viewの仕事の多くは継承元に委ねます。
このコードを注意深く見ると、ユーザーがリストアイテムをクリックしたときの振る舞いが、あることに気づきます。
2つのレイアウトのどちらが有効であるかにより、同じActivityに新しい詳細を見せるFragmentを作成し描画(FrameLayoutにFragmentを追加する)するか、(Fragmentを表示することが出来る)新しいActivityを開始する。
public static class TitlesFragment extends ListFragment {
boolean mDualPane;
int mCurCheckPosition = 0;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Populate list with our static array of titles.
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));
// Check to see if we have a frame in which to embed the details
// fragment directly in the containing UI.
View detailsFrame = getActivity().findViewById(R.id.details);
mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
if (mDualPane) {
// In dual-pane mode, the list view highlights the selected item.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Make sure our UI is in the correct state.
showDetails(mCurCheckPosition);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
}
/**
* Helper function to show the details of a selected item, either by
* displaying a fragment in-place in the current UI, or starting a
* whole new activity in which it is displayed.
*/
void showDetails(int index) {
mCurCheckPosition = index;
if (mDualPane) {
// We can display everything in-place with fragments, so update
// the list to highlight the selected item and show the data.
getListView().setItemChecked(index, true);
// Check what fragment is currently shown, replace if needed.
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(index);
// Execute a transaction, replacing any existing fragment
// with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
// Otherwise we need to launch a new activity to display
// the dialog fragment with selected text.
Intent intent = new Intent();
intent.setClass(getActivity(), DetailsActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
}
第二のフラグメント、DetailsFragmentはTitlesFragmentのリストで選択された演劇の概要を表示します。
public static class DetailsFragment extends Fragment {
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
}
ScrollView scroller = new ScrollView(getActivity());
TextView text = new TextView(getActivity());
int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
4, getActivity().getResources().getDisplayMetrics());
text.setPadding(padding, padding, padding, padding);
scroller.addView(text);
text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
return scroller;
}
}
TitlesFragmentからの再度の呼び出し、つまりもしユーザーがリストアイテムをクリックして、現在のレイアウトにR.id.details ビュー(これはDetailsFragmentsが所属する場所です)が含まれていなかったら、アプリケーションはDetailsActivityを開始し、アイテムのコンテンツを表示します。
これは、単純に演劇の概要を表示するDetailsFragmentを埋め込み縦向きのスクリーンに表示するDetailsActivityです。
public static class DetailsActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
// If the screen is now in landscape mode, we can show the
// dialog in-line with the list so we don't need this activity.
finish();
return;
}
if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
}
}
}
もし、画面が横向きであれば自分自身のActivityを終了させています。そのため、メインのActivityが引き続きDetailsFragmentと並んでTitlesFragmentを表示できます。
これは、ユーザーが最初にDetailsActivityを縦向きで表示していたが、横向きに回転させたときに発生します。(その時、現在のActivityは再起動されます)
Fragmentsを使うより多くのサンプル(及び事例の完璧なソース)はApiDemos()を見て下さい。( Samples SDK componentからダウンロードして下さい)
Except as noted, this content is licensed under Apache 2.0.