フラグメント

2011/9/15 50135hit

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.


前:OooiがStartup Weekend MatsuriTaikaiで優勝しました。 次:onSizeChanged

関連キーワード

[Android][Java][モバイル][IT][翻訳]

コメント

名前:ひさねこ|投稿日:2011/09/30 18:25

「フラグメント」の翻訳で気になった点:

「コミット後」ではなくて「コミットの内容そのもの」


英語:
the transaction is committed

トランザクションが行われるとき

トランザクションがコミットされるとき


英語:
For situations in which its okay that you lose the commit, use commitAllowingStateLoss().

コミット後の状態が失われてもいい場合はcommitAllowingStateLoss ( ) を使用します。

コミットの内容が失われてもいい場合はcommitAllowingStateLoss ( ) を使用します。


英語:
bring everything discussed in this document together

ドキュメントで議論した内容を持ち出します。

ドキュメントで議論した内容をまとめます。

※bring ・・・ together: まとめる

英語:
the application will start a new activity to show the summary, instead of loading a second fragment.

アプリケーションは新しいActivityを開始して2つめのFragmentを読み込み概要を表示します。

アプリケーションは、2つめのFragmentをロードする代わりに新しいActivityを開始して概要を表示します。

※instead of ・・・の代わりに

英語:
This fragment extends ListFragment and relies on it to handle most of the list view work.

これはListFragmentを継承し、多くはlist viewの仕事によるハンドルに委ねます。

このフラグメントは ListFragment を継承し、リストビューの処理のほとんどは ListFragment
に委ねます。


名前:ひさねこ|投稿日:2011/09/30 19:28

追加です(BY久猫)

英語:
display the DetailsFragment alongside the TitlesFragment

DetailsFragmentと並んでTitlesFragmentを表示できます

TitlesFragmentと一緒にDetailsFragmentを表示できます


※DetailsFragmentを表示できることを言いたい。


英語:
This can happen if the user begins the DetailsActivity
while in portrait orientation, but then rotates to landscape
(which restarts the current activity).

これは、ユーザーがDetailsActivityを縦向きで表示していたが、
横向きに回転させたときに発生します。(その時、現在のActivityは再起動されます)

これは、ユーザーが縦向きで DetailsActivityを開始し、
その後横向きに回転させたときに現在の Activity が再起動するため発生します。

※1.縦向きだから DetailsActivity が開始するのです。
※2.現在の Activity が再起動するため、この現象が発生するという説明が弱いです。

名前:ひさねこ|投稿日:2011/09/30 20:09

更に追加です。

私も只今フラグメントを猛勉中です ^^

直前の英文("When you perform such ・・・ that occurred")が翻訳されていないため、
唐突な文章になっています。


When you perform such a fragment transaction, you can also add it to a back stack
that's managed by the activity - each back stack entry in the activity is a record
of the fragment transaction that occurred.

The back stack allows the user to reverse a fragment transaction (navigate backwards),
by pressing the BACK key.


バックスタックはユーザーが戻るボタンを押すことでフラグメントのトランザクションを
戻せるようにします。



フラグメントのトランザクションを実行するときに、アクティビティによって管理される
バックスタックにフラグメントを追加できます。

アクティビティ内の各バックスタックのエントリは、発生したフラグメントのトランザクションの
記録といえます。

バックスタックによりユーザーは BACK キーを押すことによりフラグメントのトランザクションを
遡ること(後方へのナビゲーション)が可能です。

-----------------------------------------------------------------------------------------------

view は表示と翻訳しない方が良い。
内部的に Activity の UI は View オブジェクトの階層構造として処理される。

英語:
the activity's view hierarchy


Activityの表示階層

Activityの View 階層

----------------------------------------------------------------------------

名前:ひさねこ|投稿日:2011/09/30 20:10

-----------------------------------------------------------------------------------------------

翻訳が誤っていると思われる。

この文章の主旨は、フラグメントを挿入する方法は、XMLとコードの二通りがあるということ。

element は XML の話なので、 『 要素』と訳した方がベターではないだろうか。

英語:
You can insert a fragment into your activity layout
by declaring the fragment in the activity's layout file,
as a element, or from your application code
by adding it to an existing ViewGroup.


Activityレイアウトの一部としてFragmentを加えるとき、
Activityの表示階層内のViewGroupでビューのレイアウトを定めます。

アクティビティのレイアウトファイルに 要素としてフラグメントを宣言するか、
アプリケーションのコードで既存の ViewGroup に追加することにより、
アクティビティのレイアウトにフラグメントを挿入できます。

--------------------------------------------------------------------------------------------------

Fragment構築ではなくて、Fragmentを使用してアプリケーションを構築する方法

英語:
how to build your application to use fragments

アプリケーションでのFragment構築方法

フラグメントを使用してアプリケーションを構築する方法


--------------------------------------------------------------------------------------------------

日本語が少しおかしいと思われる。

英語:
Fragments allow such designs w

名前:ひさねこ|投稿日:2011/09/30 20:10


日本語が少しおかしいと思われる。

英語:
Fragments allow such designs without the need for you
to manage complex changes to the view hierarchy.

FragmentはView階層の複雑な変更を管理する必要なく、そのようなデザインが使用できます。

フラグメントを使用すると、ビュー階層への複雑な変更を管理せずに、
そういったデザイン(※訳注: 動的に柔軟な UI デザイン)が可能になります。

--------------------------------------------------------------------------------------------------

「・・・バックスタックの変化・・・」ではなく「変化(変更)をバックスタックに保存する」です。

英語:
By dividing the layout of an activity into fragments, you become able to modify
the activity's appearance at runtime and preserve those changes in a back stack
that's managed by the activity.

ActivityのレイアウトをFragmentに分けることによって、実行時にActivityの表示を変えたりバックスタック
の変化をActivityが管理できるようになります。

アクティビティのレイアウトをフラグメントに分けることにより、アクティビティの外観を
実行時に変更し、アクティビティが管理するバックスタックに変更を保存できます。


--------------------------------------------------------------------------------------------------

modularは形容詞。

英語:
A fragment should be a modular and reusable component in your application.

フラグメントはモジュールかつ、アプリケーション内で再利用出

名前:ひさねこ|投稿日:2011/09/30 20:10


modularは形容詞。

英語:
A fragment should be a modular and reusable component in your application.

フラグメントはモジュールかつ、アプリケーション内で再利用出来るものでなければなりません。

フラグメントはアプリケーション内のモジュール化された再利用可能なコンポーネントです。


--------------------------------------------------------------------------------------------------

using its own lifecycle callbacks が翻訳されていません。

英語:
That is, because the fragment defines its own layout and its own behavior
using its own lifecycle callbacks, you can include one fragment in multiple activities.

つまり、Fragmentはそれ自身のレイアウトと振る舞いを確立しているので、
複数の異なるActivityで同じFragmentを使う事が出来ます。

つまり、フラグメントは自分自身のライフサイクルのコールバックメソッドを使用して
自分自身のレイアウトと振る舞いを定義するので、複数のアクティビティで同じ
フラグメントを再利用できるのです。

名前:ひさねこ|投稿日:2011/09/30 20:11

投稿が汚くなって申し訳ございません m(__)m

名前:ひさねこ|投稿日:2011/10/03 12:11

残りを2回に分けて投稿します。参考になれば幸いです。
==================================================================================================
※タイプミス
onCreate(),onStart(),onPauseそしてonStopなど

onCreate(),onStart(),onPause()そしてonStop()など
--------------------------------------------------------------------------------------------------
※"This is usually where you should commit"の部分の翻訳が改善できる
英語:This is usually where you should commit any changes that should be persisted beyond the current user session
通常、ユーザーセッションを越えるあらゆる変化を確定させる必要があります

通常、現在のユーザーセッションを超えて永続化すべき変更はここでコミットするのが良いでしょう
--------------------------------------------------------------------------------------------------
※「ユーザーが除外されたFragment」という表現が良く分からない。allow:〔+目+to do〕〈人が〉〈…するのを〉可能にする.
英語:allowing the user to return to a dismissed fragment.
ユーザーが除外されたFragmentに戻ることを許可するためです。

ユーザーが離れたフラグメントに戻れるからです。
--------------------------------------------------------------------------------------------------
※ contribute: 提供する
英語:A fragment is usually u

名前:ひさねこ|投稿日:2011/10/03 12:12

すみません。2回では無理そうなので、数回に分けます。

※ contribute: 提供する
英語:A fragment is usually used as part of an activity's user interface and contributes its own layout to the activity.
Fragmentは大抵Activityのレイアウトに影響しユーザーインターフェイスの一部となります。

通常、フラグメントはアクティビティの UI 部品として使用され、レイアウトをアクティビティに提供します。
--------------------------------------------------------------------------------------------------
※ "your fragment is" が翻訳されていない。
英語: Note: If your fragment is a subclass of ListFragment, the default implementation returns a ListView from onCreateView(), so you don't need to implement it.
ノート;もし、ListFragmentを継承した場合、標準でonCreateView()がListViewを戻します。そのため、あなたはそれを実装する必要がありません。

注意: フラグメントが ListFragment のサブクラスの場合、デフォルトの実装では onCreateView() は ListView を返すので、onCreateView() メソッドを実装する必要はありません。
--------------------------------------------------------------------------------------------------
※ "parameter"が翻訳されていない。
英語: The container parameter passed to onCreateView() is the parent ViewGroup (from the activity's layout) in

名前:ひさねこ|投稿日:2011/10/03 12:12

※ "parameter"が翻訳されていない。
英語: The container parameter passed to onCreateView() is the parent ViewGroup (from the activity's layout) in which your fragment layout will be inserted.

onCreateView()に渡されるcontainerは(ActivityLayoutによる)親のViewGroupです。Fragmentのレイアウトはこれに入ります。

onCreateView()に渡される container パラメーターは、フラグメントのレイアウトが挿入される、(アクティビティのレイアウト内の)親 ViewGroupです。
--------------------------------------------------------------------------------------------------
※ タイプミス
インフレとされたレイアウト→インフレートされたレイアウト
インフレとレイアウト→インフレートレイアウト
インフレとされたレイアウトをコンテナに入れている→インフレートされたレイアウトをcontainerに入れている
--------------------------------------------------------------------------------------------------
in place of the element: 要素の位置に
英語: The system inserts the View returned by the fragment directly in place of the element.
システムはFragmentに代わり、Fragmentが返すViewを直接挿入します。

システムはフラグメントが返した View を直接 要素の位置に挿入します。

名前:ひさねこ|投稿日:2011/10/03 12:12

※"you can use to capture the fragment to" が翻訳されていない
英語: and which you can use to capture the fragment to perform transactions, such as remove it
なおかつ、Fragmentが取り除かれるときにあなたがトランザクション処理を行えるように

そして、この ID はフラグメントの削除などのトランザクションを行うときにフラグメントを取得するのに使用できます
--------------------------------------------------------------------------------------------------
※"エフェクトの変化"とは何か?
英語: you must call commit() for the changes to take effect.
エフェクトの変化のためにcommit()メソッドをコールする必要があります。

変更を有効にするためには commit() メソッドをコールする必要があります。
--------------------------------------------------------------------------------------------------
※「ActivityをFragmentに加えること」→誤訳
英語: A great feature about using fragments in your activity is the ability to add, remove, replace, and perform other actions with them, in response to user interaction.
ActivityをFragmentに加えることによりユーザーインタラクションに応じたFragmentの追加、削除、置き換えそしてその他アクションを行う能力がもたらされます。

アクティビティ内でのフラグメント使用は、ユーザー操作に反応してフラグメントの追加、削除、置換、その他アクションを行える点が優れています。

名前:ひさねこ|投稿日:2011/10/03 12:13

※called a transaction:トランザクションと呼ばれます
英語: Each set of changes that you commit to the activity is called a transaction
各Activityに対する変化のトランザクションが確定されます。

アクティビティにコミットする変更の各まとまりはトランザクションと呼ばれます。
--------------------------------------------------------------------------------------------------
※タイプミス: Commit
英語: Calling commit() does not perform the transaction immediately.
Commitが呼ばれると即時にTransactionが実行されるわけではありません。

commit() を呼び出しても、即座に Transaction は実行されません。
--------------------------------------------------------------------------------------------------
※スケジュールされる内容は"run on the activity's UI thread ・・・"
英語: Rather, it schedules it to run on the activity's UI thread (the "main" thread) as soon as the thread is able to do so.
スレッドが実行可能になるまでActivityのUIスレッド(メインスレッド)にスケジュールされます。

むしろ、可能になればすぐにアクティビティの UI スレッド(メインスレッド)上でトランザクションが実行されるようにスケジュールされます。
--------------------------------------------------------------------------------------------------
※主語(the transaction)が翻訳されていません。
英語: u

名前:ひさねこ|投稿日:2011/10/03 12:13

これで最後です!

※主語(the transaction)が翻訳されていません。
英語: unless the transaction is a dependency for jobs in other threads
他のスレッドのジョブに依存するようなことがない限り

トランザクションが(メインスレッド以外の)他のスレッドのジョブに依存しない限り
--------------------------------------------------------------------------------------------------

名前:ひさねこ|投稿日:2011/10/03 12:19

何度もすみません。間違えて下の記事に投稿してしまいました(再投稿します)。
------------------------------------------
半角の"<"">"で囲まれた部分が飛んでいたので、全角にして再投稿します。すみませんm(__)m

in place of the <fragment> element:<fragment> 要素の位置に
英語: The system inserts the View returned by the fragment directly in place of the <fragment> element.
システムはFragmentに代わり、Fragmentが返すViewを直接挿入します。

システムはフラグメントが返した View を直接 <fragment> 要素の位置に挿入します。

名前:kenz|投稿日:2011/10/06 20:44

沢山のご指摘ありがとうございます。
英語は苦手なので本当に参考になります。
今後はもっと読みやすく翻訳できるよう、努力して参ります。

コメントを投稿する

名前URI
コメント