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を追加して、タブレットとスマートフォンで異なる画面構成にしてみましょう。