MapFragmentをカスタマイズする
Google Mapを表示するクラスは、Fragmentで提供されています。今度は、このFragmentを利用して、タブレットとスマートフォンで画面構成を変えてみましょう。
ここまでは、あまりFragmentを意識せずに、従来どおりActivityにすべてを実装する形にしていました。画面の構成が1画面であれば、これでも構わないのですが、複数のFragmentを利用する場合では、UIの処理をFragment自身に実装するほうがすっきりするでしょう。
そこで今回は、まず地図のUI処理を、MapFragmentを継承した独自のFragmentクラスに移してみることにします。
Fragmentのライフサイクル
具体的なコードを紹介する前に、Fragmentのライフサイクルについて、ざっと説明しておきましょう。
通常では、ActivityとFragmentのライフサイクルは次のような関係になっています。
Fragmentは、単独で存在することはできません。必ず紐付いているActivityが必要です。そのActivityのライフサイクルに応じた、Fragmentのライフサイクルがあります。
Fragmentでは、Activityよりも多くのコールバックメソッドがあります。次の表に、Fragmentだけにあるメソッドのうち、主なものをあげてみました。
| メソッド名 | タイミングなど |
|---|---|
| onAttach() | Activityに紐付けられたときに(一度だけ)呼ばれる |
| onCreateView() | View階層に関連付けられるときに呼ばれる。表示するViewを返す |
| onActivityCreated() | 紐付いているActivityのonCreate()が呼ばれた直後に呼ばれる |
| onDetach() | Activityとの紐付けが解除されたときに呼ばれる |
onCreateメソッドは、Fragment自身の初期化時に呼ばれるメソッドです。従来ActivityのonCreateメソッドで記述していた処理は、onActivityCreatedメソッドに記述するようにします。
MyMapFragmentクラス
最初に、MapFragmentを継承したMyMapFragmentクラスを作成します。このクラスには、もとのActivityから、LoaderCallbacksインターフェースを実装したメソッド以外、すべてを移します。
public class MyMapFragment extends MapFragment {
~中略~
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ekiMarkerMap = new HashMap<Marker, EkiInfo>();
setRetainInstance(true); // フラグメントを保存する
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
try {
// マップオブジェクトを取得する
googleMap = getMap();
// 初期設定がまだなら(1)
if (centerPosition == null) {
mapInit();
}
// 地図の中心位置を取得する
centerPosition = googleMap.getCameraPosition();
// 最寄り駅情報を取得する
execMoyori(centerPosition);
// 地図を移動したときのリスナー
googleMap.setOnCameraChangeListener(new OnCameraChangeListener() {
~中略~
});
googleMap.setOnInfoWindowClickListener(
~中略~
);
}
// GoogleMapが使用できないとき
catch (Exception e) {
}
}
~後略~
前述のとおり、onCreateメソッドのみに記述していた処理を、MyMapFragmentでは、onCreateメソッドとonActivityCreatedメソッドに分けています。
なお、FragmentをsetRetainInstanceメソッドで保存するように設定した場合、ライフサイクルに注意が必要です。Fragmentを保存していると、Activityの状態にかかわらず、インスタンスが破棄されなくなります。端末を回転させた場合でも破棄されないため、onCreateメソッドは、起動時の一度きりしか呼ばれません(onDestroyメソッドも同様に呼ばれない)。ただしそれ以外のメソッドは、Activityの状態に応じてコールバックされます。
また、Fragmentを保存していると、onActivityCreatedの引数savedInstanceStateも、常にNULLになります。このサンプルでは、Fragmentがすでに生成されているかどうかを、フィールドのcenterPositionの値で判断するようにしています(1)。
Loaderの処理
Loaderは、Fragmentでも利用することができます。
public void execMoyori(CameraPosition centerPosition) {
~中略~
// LoaderManagerの初期化(1)
getLoaderManager().restartLoader(0, bundle, (MainActivity)getActivity());
}
今回は、LoaderのコールバックのみをActivityに実装し、restartLoaderメソッドの第3引数を、Activityに変更します(1)。
最後に
今回は、Google Mapsのイベントリスナー処理と、MapFragmentをカスタマイズする方法を解説しました。次回は、最寄り駅の一覧を表示するFragmentを追加して、タブレットとスマートフォンで異なる画面構成にしてみましょう。
