2011/07/31

PhoneとTabletで設定メニューを共有する

Paplicoを作成していてふと気付いたことが。

Compatibility PackageにはPreferenceFragmentが無い!


PreferenceFragmentが使えるなら同じ設定画面を使い回すことが出来ると思ったのですが、どうやらPhone向けのPreferenceActivityとTablet向けの2ペインPreferenceActivityを別に作成する必要があるみたいです。
(注:ちゃんと調べてないので、もっと楽な方法があるのかも。知ってたら教えて下さい)



今回作成する設定メニューの構造はこちら


これをTabletで表示するとこんな感じ。


Phoneの方の見た目は省略(というか言わずもがな)。
Phoneでは設定画面のトップメージで「メニュー1」と「メニュー2」だけが表示される形になります。


今回のサンプルAPK及び作成したプロジェクトはこちら


・AndroidManifest.xml


今回利用するActivityは
・Main・・・PhoneかTabletかを判断して起動するメニューを分けるだけのActivity。

Phone用
・PreferenceHeader・・・スマートフォンで表示する設定メニューのトップページ。
・PreferenceActivity1・・・スマートフォンで表示する設定メニューの詳細ページ1
・PreferenceActivity1・・・スマートフォンで表示する設定メニューの詳細ページ2

Tablet用
・MainPreference・・・タブレットで表示する設定メニュー


・利用するXMLについて

まずはタブレットで利用するXMLについて。
タブレットでは2ペインのメニュー構成になっていますが、これを実現するのは非常に単純で、左ペインのヘッダー部分も右ペインの詳細メニューも共にXMLで構成することができます。

今回タブレットで使用する設定画面のXMLは全部で3つです。
・ヘッダー部分(左ペイン)
res/xml-xlarge-v11/preference_header.xml

このheaderというのはAPI11で追加されたPreferenceActivity$Headerのことで、もうちょっと詳しい使用例はこちらに載っています。
今回はheaderタグ内のfragmentに右ペインに表示するPreferenceFragmentのパスを指定しているだけですが、IntentでWebを開くとかヘッダーの左にアイコンを表示するとか、もっと色々出来るらしいです。
ただしこれはCompatibility Packageでも利用できないため、API11以降専用になります。
なおXMLファイルのフォルダから分かる通り、このXMLはXLARGE画面を持ったAPI11以降専用のXMLです。

・詳細1
res/xml/preference1.xml

PreferenceScreenが二つあるだけのいたって普通な設定画面XMLです。このXMLはスマートフォン、タブレット共用になります。
@string等のリソース詳細は割愛します。

・詳細2
res/xml/preference2.xml
詳細1と全く同じなので割愛します。


次にスマートフォンについて。
スマートフォンで利用する設定画面XMLも3つですが、詳細1・2はタブレットと共用です。スマートフォン専用で必要なのはトップページのヘッダー部分だけになります。

・ヘッダー部分
res/xml/preference_header.xml

ヘッダーを構成するPreferenceScreenが二つあり、それぞれクリックすると詳細のActivityを起動します。


・Javaについて

Androidで設定画面を利用する時にはPreferenceActivityのonCreateでaddPreferenceFromResourceを呼んで設定画面を定義したXMLを利用すると思います。今回利用するのもこの流れと全く同じなのですが、タブレットで2ペイン画面を構成するには右ペインにPreferenceFragmentを設置する必要があります。

PreferenceFragmentの利用方法はPreferenceActivityと基本的には同じで、

特に特別な処理する必要の無い設定画面であればこれだけです。
今回の趣旨は従来の、PreferenceFragmentを利用できないAndroid OSで如何に楽をして設定画面を作成するかになります。

どうすれば楽にPreferenceFragmentとPreferenceActivityの中身を融合できるのか。。。

・PreferenceWrapper.java

どちらかしか使えないので、それらから必要なメソッドを取得するクラス作ればいいじゃない!←結論
簡単な設定メニューを作成するだけであればaddPreferencesFromResource、findPreference、getStringさえ利用出来ればいいので、今回はこれらだけを含んだクラスを作成しました。


あとはこれを
・BasePreference.java

こんな感じの抽象クラスを作成して、これを実際のPreferenceActivityやPreferenceFragmentの中身にします。

・BasePhonePreferenceActivity.java

これを本当に作成すべきかは分かりませんが、こんな感じでPreferenceActivity/PreferenceFragment共に継承元のクラスを作成しておくと後でメンテがしやすい様な気がします。BasePreferenceFragmentは割愛します。


次に、タブレットでマルチペイン設定画面を構成する方法ですが、
・MainPreference.java

特に特別なことをしないならばこれだけでマルチペインの設定画面になります。
PreferenceActivity#onBuildHeadersでloadHeadersFromResourceに先程preference-headerをルートで作成したXMLを指定するだけです。各設定の詳細はPreferenceFragment内で行われるため、基本的にベースとなるPreferenceActivityでは何もする必要はありません。


設定画面をクリックしたりした際の挙動をどこかで記述する必要がありますが、それは先程紹介したBasePreferenceを継承したクラスの中で行います。
・Preference1.java

簡単な例となりますが、こんな感じ。普段PreferenceActivity#onCreateで行っている処理がこのクラスのonCreateで行います。まずaddPreferencesFromResourceメソッドを呼びXMLを指定し、その後実際の処理をつらつらと。


あとはこれを
・PreferenceActivity1.java

こんな感じで利用すれば、設定メニューが完成します。PreferenceFragmentを継承した方のクラスも全く同じ方法です。



簡単でしょ!

最後の方が雑?
じゃっかんめんどうくさくなっt

2011/07/26

アプリのSD移動について

Android2.2(API8-)で対応したアプリのSD移動について、

ビルドSDKを8以上にしAndroidManifest.xmlにinstallLocation="internalOnly"を明示しない限り、目の付け所が違う某メーカーの端末にのみ存在する「優先インストール先」設定で「microSD」を指定された場合、アプリをSDに移動できてしまう。端末側の設定に依存してSDカードへのインストールを許す場合がある。


SD移動すべきでないアプリ(ホームウィジェットやサービスを利用するアプリ)はinstallLocation="internalOnly"を明示すべきである。


ちなみにAndroid3.0にはアプリのSD移動機能がありません。
(おそらくmicroSDのサポート自体が3.0リリース当初は無かったための措置)

3.1以降は出来る。。。?
(3.1は未確認ですが、3.2には「SDへ移動」の項目が存在します)


以下、どうでもいい検証
targetAPI=7, installLocation記述なしアプリについて、

1.優先がmicroSDの時にインストールした場合
PackageManagerから取得できるinstallLocationの値は「移動可能」

2.優先がシステム判断の時にインストールした場合
PackageManagerから取得できるinstallLocationの値は「移動不可能」

3.優先がシステム判断の時にインストール >> インストール後に優先をmicroSDに変更
PackageManagerから取得できるinstallLocationの値は「移動不可能」だが
Androidの設定からはアプリをSDに移動できる


ちなみにinstallLocationの値自体はAPI8ではPackageManagerから取得できるPackageInfo、API9-ではApplicationInfoから取得できます。リフレクションで。


優先インストール先の設定はコマンドラインから
pm setInstallLocation -(数字)
で可能です。

The setInstallLocation command changes the default install location
0 [auto]: Let system decide the best location
1 [internal]: Install on internal device storage
2 [external]: Install on external media

だそうな。

adb shell pm setInstallLocation 2
で通ると優先インストール先がmicroSDになりinstallLocationを指定していないアプリはSDへ移動可能に。

2011/07/22

フラグメントのライフサイクルとかメモ 2

トランザクション等イマイチ自身の理解に欠ける部分が多いため、とりあえず色々挙動を見てみた。
(色々と言うほども無いけれど。。。)


FragmentTransactionのaddとreplaceって何が違うんだろうか、的な。


結論:
・addを呼ぶと純粋にFragmentを2枚重ねるイメージ。Activityの状態遷移と同時に二つのFragmentの状態も変わっていく。
・replaceは先にあるFragment1のViewを破棄した後に呼んだFragment2のViewを作成する。Fragment1はAttachしているActivityがonPauseに入るタイミングでFragment2と同時にonSaveInstanceStateが呼ばれ状態が保存されるが、再びFragment1がトップになるまでは呼ばれない。


動き:
1.アプリを開くとActivity1が起動する
2.Activity1がFragment1を自動的にAttachする
3.Fragment1上のボタンを押すとFragment2をActivity1でFragment1がAttachしているViewにadd/replaceする
4.Fragment2上のボタンを押すとActivity2を起動する
5.Activity2はFragment3を自動的にAttachする
6.Fragment3上のボタンを押すとActivity2が終了する
7.戻る連打でアプリを終了させる


*** FragmentTransaction#add ***

Activity2を起動しない場合

07-22 06:48:16.317: DEBUG/TEST(31299): Activity_1 : onCreate
07-22 06:48:16.377: DEBUG/TEST(31299): Activity_1 : onStart
07-22 06:48:16.377: DEBUG/TEST(31299): Fragment_1 : onAttach
07-22 06:48:16.377: DEBUG/TEST(31299): Activity_1 : onAttachFragment
07-22 06:48:16.377: DEBUG/TEST(31299): Fragment_1 : onCreate
07-22 06:48:16.377: DEBUG/TEST(31299): Fragment_1 : onCreateView
07-22 06:48:16.377: DEBUG/TEST(31299): Fragment_1 : onActivityCreated
07-22 06:48:16.387: DEBUG/TEST(31299): Fragment_1 : onStart
07-22 06:48:16.387: DEBUG/TEST(31299): Activity_1 : onPostCreate
07-22 06:48:16.387: DEBUG/TEST(31299): Activity_1 : onResume
07-22 06:48:16.387: DEBUG/TEST(31299): Fragment_1 : onResume

07-22 06:48:19.367: DEBUG/TEST(31299): Fragment_1 : onClick
07-22 06:48:19.407: DEBUG/TEST(31299): Fragment_2 : onAttach
07-22 06:48:19.407: DEBUG/TEST(31299): Activity_1 : onAttachFragment
07-22 06:48:19.407: DEBUG/TEST(31299): Fragment_2 : onCreate
07-22 06:48:19.407: DEBUG/TEST(31299): Fragment_2 : onCreateView
07-22 06:48:19.427: DEBUG/TEST(31299): Fragment_2 : onActivityCreated
07-22 06:48:19.427: DEBUG/TEST(31299): Fragment_2 : onStart
07-22 06:48:19.427: DEBUG/TEST(31299): Fragment_2 : onResume

07-22 06:48:20.387: DEBUG/TEST(31299): Activity_1 : onBackPressed
07-22 06:48:20.387: DEBUG/TEST(31299): Fragment_2 : onPause
07-22 06:48:20.387: DEBUG/TEST(31299): Fragment_2 : onStop
07-22 06:48:20.387: DEBUG/TEST(31299): Fragment_2 : onDestroyView
07-22 06:48:20.387: DEBUG/TEST(31299): Fragment_2 : onDestroy
07-22 06:48:20.387: DEBUG/TEST(31299): Fragment_2 : onDetach

07-22 06:48:20.777: DEBUG/TEST(31299): Activity_1 : onBackPressed
07-22 06:48:20.787: DEBUG/TEST(31299): Activity_1 : onPause
07-22 06:48:20.787: DEBUG/TEST(31299): Fragment_1 : onPause
07-22 06:48:20.887: DEBUG/TEST(31299): Activity_1 : onStop
07-22 06:48:20.887: DEBUG/TEST(31299): Fragment_1 : onStop
07-22 06:48:20.887: DEBUG/TEST(31299): Activity_1 : onDestroy
07-22 06:48:20.887: DEBUG/TEST(31299): Fragment_1 : onDestroyView
07-22 06:48:20.887: DEBUG/TEST(31299): Fragment_1 : onDestroy
07-22 06:48:20.887: DEBUG/TEST(31299): Fragment_1 : onDetach


起動する場合
。。。ここで色塗り力尽きる。

07-22 06:54:46.407: DEBUG/TEST(31299): Activity_1 : onCreate
07-22 06:54:46.457: DEBUG/TEST(31299): Activity_1 : onStart
07-22 06:54:46.457: DEBUG/TEST(31299): Fragment_1 : onAttach
07-22 06:54:46.457: DEBUG/TEST(31299): Activity_1 : onAttachFragment
07-22 06:54:46.457: DEBUG/TEST(31299): Fragment_1 : onCreate
07-22 06:54:46.457: DEBUG/TEST(31299): Fragment_1 : onCreateView
07-22 06:54:46.497: DEBUG/TEST(31299): Fragment_1 : onActivityCreated
07-22 06:54:46.497: DEBUG/TEST(31299): Fragment_1 : onStart
07-22 06:54:46.497: DEBUG/TEST(31299): Activity_1 : onPostCreate
07-22 06:54:46.497: DEBUG/TEST(31299): Activity_1 : onResume
07-22 06:54:46.497: DEBUG/TEST(31299): Fragment_1 : onResume

07-22 06:54:47.747: DEBUG/TEST(31299): Fragment_1 : onClick
07-22 06:54:47.747: DEBUG/TEST(31299): Fragment_2 : onAttach
07-22 06:54:47.747: DEBUG/TEST(31299): Activity_1 : onAttachFragment
07-22 06:54:47.747: DEBUG/TEST(31299): Fragment_2 : onCreate
07-22 06:54:47.747: DEBUG/TEST(31299): Fragment_2 : onCreateView
07-22 06:54:47.747: DEBUG/TEST(31299): Fragment_2 : onActivityCreated
07-22 06:54:47.747: DEBUG/TEST(31299): Fragment_2 : onStart
07-22 06:54:47.747: DEBUG/TEST(31299): Fragment_2 : onResume

07-22 06:54:48.457: DEBUG/TEST(31299): Fragment_2 : onClick
07-22 06:54:48.467: DEBUG/TEST(31299): Activity_1 : onSaveInstanceState
07-22 06:54:48.467: DEBUG/TEST(31299): Fragment_1 : onSaveInstanceState
07-22 06:54:48.467: DEBUG/TEST(31299): Fragment_2 : onSaveInstanceState
07-22 06:54:48.467: DEBUG/TEST(31299): Activity_1 : onPause
07-22 06:54:48.467: DEBUG/TEST(31299): Fragment_1 : onPause
07-22 06:54:48.477: DEBUG/TEST(31299): Fragment_2 : onPause
07-22 06:54:48.487: DEBUG/TEST(31299): Activity_2 : onCreate
07-22 06:54:48.497: DEBUG/TEST(31299): Activity_2 : onStart
07-22 06:54:48.497: DEBUG/TEST(31299): Fragment_3 : onAttach
07-22 06:54:48.497: DEBUG/TEST(31299): Activity_2 : onAttachFragment
07-22 06:54:48.497: DEBUG/TEST(31299): Fragment_3 : onCreate
07-22 06:54:48.497: DEBUG/TEST(31299): Fragment_3 : onCreateView
07-22 06:54:48.497: DEBUG/TEST(31299): Fragment_3 : onActivityCreated
07-22 06:54:48.497: DEBUG/TEST(31299): Fragment_3 : onStart
07-22 06:54:48.497: DEBUG/TEST(31299): Activity_2 : onPostCreate
07-22 06:54:48.497: DEBUG/TEST(31299): Activity_2 : onResume
07-22 06:54:48.497: DEBUG/TEST(31299): Fragment_3 : onResume
07-22 06:54:48.637: DEBUG/TEST(31299): Activity_1 : onStop
07-22 06:54:48.637: DEBUG/TEST(31299): Fragment_1 : onStop
07-22 06:54:48.637: DEBUG/TEST(31299): Fragment_2 : onStop

07-22 06:54:49.257: DEBUG/TEST(31299): Fragment_3 : onClick
07-22 06:54:49.257: DEBUG/TEST(31299): Activity_2 : finish
07-22 06:54:49.277: DEBUG/TEST(31299): Activity_2 : onPause
07-22 06:54:49.277: DEBUG/TEST(31299): Fragment_3 : onPause
07-22 06:54:49.287: DEBUG/TEST(31299): Activity_1 : onActivityResult
07-22 06:54:49.287: DEBUG/TEST(31299): Fragment_2 : onActivityResult
07-22 06:54:49.287: DEBUG/TEST(31299): Activity_1 : onRestart
07-22 06:54:49.287: DEBUG/TEST(31299): Activity_1 : onStart
07-22 06:54:49.287: DEBUG/TEST(31299): Fragment_1 : onStart
07-22 06:54:49.287: DEBUG/TEST(31299): Fragment_2 : onStart
07-22 06:54:49.287: DEBUG/TEST(31299): Activity_1 : onResume
07-22 06:54:49.287: DEBUG/TEST(31299): Fragment_1 : onResume
07-22 06:54:49.287: DEBUG/TEST(31299): Fragment_2 : onResume
07-22 06:54:49.407: DEBUG/TEST(31299): Activity_2 : onStop
07-22 06:54:49.407: DEBUG/TEST(31299): Fragment_3 : onStop
07-22 06:54:49.407: DEBUG/TEST(31299): Activity_2 : onDestroy
07-22 06:54:49.407: DEBUG/TEST(31299): Fragment_3 : onDestroyView
07-22 06:54:49.407: DEBUG/TEST(31299): Fragment_3 : onDestroy
07-22 06:54:49.407: DEBUG/TEST(31299): Fragment_3 : onDetach

07-22 06:54:49.997: DEBUG/TEST(31299): Activity_1 : onBackPressed
07-22 06:54:49.997: DEBUG/TEST(31299): Fragment_2 : onPause
07-22 06:54:49.997: DEBUG/TEST(31299): Fragment_2 : onStop
07-22 06:54:49.997: DEBUG/TEST(31299): Fragment_2 : onDestroyView
07-22 06:54:49.997: DEBUG/TEST(31299): Fragment_2 : onDestroy
07-22 06:54:49.997: DEBUG/TEST(31299): Fragment_2 : onDetach

07-22 06:54:50.997: DEBUG/TEST(31299): Activity_1 : onBackPressed
07-22 06:54:51.007: DEBUG/TEST(31299): Activity_1 : onPause
07-22 06:54:51.007: DEBUG/TEST(31299): Fragment_1 : onPause
07-22 06:54:51.287: DEBUG/TEST(31299): Activity_1 : onStop
07-22 06:54:51.287: DEBUG/TEST(31299): Fragment_1 : onStop
07-22 06:54:51.287: DEBUG/TEST(31299): Activity_1 : onDestroy
07-22 06:54:51.287: DEBUG/TEST(31299): Fragment_1 : onDestroyView
07-22 06:54:51.287: DEBUG/TEST(31299): Fragment_1 : onDestroy
07-22 06:54:51.287: DEBUG/TEST(31299): Fragment_1 : onDetach


*** FragmentTransaction#replace ***

Activity2を起動しない場合

07-22 07:08:44.957: DEBUG/TEST(32444): Activity_1 : onCreate
07-22 07:08:44.987: DEBUG/TEST(32444): Activity_1 : onStart
07-22 07:08:45.017: DEBUG/TEST(32444): Fragment_1 : onAttach
07-22 07:08:45.017: DEBUG/TEST(32444): Activity_1 : onAttachFragment
07-22 07:08:45.017: DEBUG/TEST(32444): Fragment_1 : onCreate
07-22 07:08:45.017: DEBUG/TEST(32444): Fragment_1 : onCreateView
07-22 07:08:45.037: DEBUG/TEST(32444): Fragment_1 : onActivityCreated
07-22 07:08:45.037: DEBUG/TEST(32444): Fragment_1 : onStart
07-22 07:08:45.037: DEBUG/TEST(32444): Activity_1 : onPostCreate
07-22 07:08:45.037: DEBUG/TEST(32444): Activity_1 : onResume
07-22 07:08:45.047: DEBUG/TEST(32444): Fragment_1 : onResume

07-22 07:08:48.097: DEBUG/TEST(32444): Fragment_1 : onClick
07-22 07:08:48.117: DEBUG/TEST(32444): Fragment_1 : onPause
07-22 07:08:48.117: DEBUG/TEST(32444): Fragment_1 : onStop
07-22 07:08:48.117: DEBUG/TEST(32444): Fragment_1 : onDestroyView
07-22 07:08:48.137: DEBUG/TEST(32444): Fragment_2 : onAttach
07-22 07:08:48.137: DEBUG/TEST(32444): Activity_1 : onAttachFragment
07-22 07:08:48.137: DEBUG/TEST(32444): Fragment_2 : onCreate
07-22 07:08:48.137: DEBUG/TEST(32444): Fragment_2 : onCreateView
07-22 07:08:48.147: DEBUG/TEST(32444): Fragment_2 : onActivityCreated
07-22 07:08:48.147: DEBUG/TEST(32444): Fragment_2 : onStart
07-22 07:08:48.147: DEBUG/TEST(32444): Fragment_2 : onResume

07-22 07:08:50.337: DEBUG/TEST(32444): Activity_1 : onBackPressed
07-22 07:08:50.337: DEBUG/TEST(32444): Fragment_2 : onPause
07-22 07:08:50.337: DEBUG/TEST(32444): Fragment_2 : onStop
07-22 07:08:50.337: DEBUG/TEST(32444): Fragment_2 : onDestroyView
07-22 07:08:50.337: DEBUG/TEST(32444): Fragment_2 : onDestroy
07-22 07:08:50.337: DEBUG/TEST(32444): Fragment_2 : onDetach
07-22 07:08:50.337: DEBUG/TEST(32444): Fragment_1 : onCreateView
07-22 07:08:50.347: DEBUG/TEST(32444): Fragment_1 : onActivityCreated
07-22 07:08:50.347: DEBUG/TEST(32444): Fragment_1 : onStart
07-22 07:08:50.347: DEBUG/TEST(32444): Fragment_1 : onResume

07-22 07:08:50.827: DEBUG/TEST(32444): Activity_1 : onBackPressed
07-22 07:08:51.207: DEBUG/TEST(32444): Activity_1 : onPause
07-22 07:08:51.207: DEBUG/TEST(32444): Fragment_1 : onPause
07-22 07:08:51.417: DEBUG/TEST(32444): Activity_1 : onStop
07-22 07:08:51.417: DEBUG/TEST(32444): Fragment_1 : onStop
07-22 07:08:51.417: DEBUG/TEST(32444): Activity_1 : onDestroy
07-22 07:08:51.417: DEBUG/TEST(32444): Fragment_1 : onDestroyView
07-22 07:08:51.417: DEBUG/TEST(32444): Fragment_1 : onDestroy
07-22 07:08:51.417: DEBUG/TEST(32444): Fragment_1 : onDetach


Activity2を起動する場合

07-22 07:09:58.637: DEBUG/TEST(32444): Activity_1 : onCreate
07-22 07:09:58.657: DEBUG/TEST(32444): Activity_1 : onStart
07-22 07:09:58.657: DEBUG/TEST(32444): Fragment_1 : onAttach
07-22 07:09:58.657: DEBUG/TEST(32444): Activity_1 : onAttachFragment
07-22 07:09:58.657: DEBUG/TEST(32444): Fragment_1 : onCreate
07-22 07:09:58.657: DEBUG/TEST(32444): Fragment_1 : onCreateView
07-22 07:09:58.667: DEBUG/TEST(32444): Fragment_1 : onActivityCreated
07-22 07:09:58.667: DEBUG/TEST(32444): Fragment_1 : onStart
07-22 07:09:58.667: DEBUG/TEST(32444): Activity_1 : onPostCreate
07-22 07:09:58.667: DEBUG/TEST(32444): Activity_1 : onResume
07-22 07:09:58.667: DEBUG/TEST(32444): Fragment_1 : onResume

07-22 07:09:59.447: DEBUG/TEST(32444): Fragment_1 : onClick
07-22 07:09:59.467: DEBUG/TEST(32444): Fragment_1 : onPause
07-22 07:09:59.467: DEBUG/TEST(32444): Fragment_1 : onStop
07-22 07:09:59.467: DEBUG/TEST(32444): Fragment_1 : onDestroyView
07-22 07:09:59.467: DEBUG/TEST(32444): Fragment_2 : onAttach
07-22 07:09:59.467: DEBUG/TEST(32444): Activity_1 : onAttachFragment
07-22 07:09:59.467: DEBUG/TEST(32444): Fragment_2 : onCreate
07-22 07:09:59.467: DEBUG/TEST(32444): Fragment_2 : onCreateView
07-22 07:09:59.467: DEBUG/TEST(32444): Fragment_2 : onActivityCreated
07-22 07:09:59.467: DEBUG/TEST(32444): Fragment_2 : onStart
07-22 07:09:59.467: DEBUG/TEST(32444): Fragment_2 : onResume

07-22 07:09:59.927: DEBUG/TEST(32444): Fragment_2 : onClick
07-22 07:09:59.957: DEBUG/TEST(32444): Activity_1 : onSaveInstanceState
07-22 07:09:59.957: DEBUG/TEST(32444): Fragment_1 : onSaveInstanceState
07-22 07:09:59.957: DEBUG/TEST(32444): Fragment_2 : onSaveInstanceState
07-22 07:09:59.957: DEBUG/TEST(32444): Activity_1 : onPause
07-22 07:09:59.957: DEBUG/TEST(32444): Fragment_2 : onPause
07-22 07:09:59.967: DEBUG/TEST(32444): Activity_2 : onCreate
07-22 07:09:59.967: DEBUG/TEST(32444): Activity_2 : onStart
07-22 07:09:59.967: DEBUG/TEST(32444): Fragment_3 : onAttach
07-22 07:09:59.967: DEBUG/TEST(32444): Activity_2 : onAttachFragment
07-22 07:09:59.967: DEBUG/TEST(32444): Fragment_3 : onCreate
07-22 07:09:59.967: DEBUG/TEST(32444): Fragment_3 : onCreateView
07-22 07:09:59.977: DEBUG/TEST(32444): Fragment_3 : onActivityCreated
07-22 07:09:59.977: DEBUG/TEST(32444): Fragment_3 : onStart
07-22 07:09:59.977: DEBUG/TEST(32444): Activity_2 : onPostCreate
07-22 07:09:59.977: DEBUG/TEST(32444): Activity_2 : onResume
07-22 07:09:59.977: DEBUG/TEST(32444): Fragment_3 : onResume
07-22 07:10:00.117: DEBUG/TEST(32444): Activity_1 : onStop
07-22 07:10:00.117: DEBUG/TEST(32444): Fragment_2 : onStop

07-22 07:10:00.277: DEBUG/TEST(32444): Fragment_3 : onClick
07-22 07:10:00.277: DEBUG/TEST(32444): Activity_2 : finish
07-22 07:10:00.287: DEBUG/TEST(32444): Activity_2 : onPause
07-22 07:10:00.287: DEBUG/TEST(32444): Fragment_3 : onPause
07-22 07:10:00.297: DEBUG/TEST(32444): Activity_1 : onActivityResult
07-22 07:10:00.297: DEBUG/TEST(32444): Fragment_2 : onActivityResult
07-22 07:10:00.297: DEBUG/TEST(32444): Activity_1 : onRestart
07-22 07:10:00.297: DEBUG/TEST(32444): Activity_1 : onStart
07-22 07:10:00.297: DEBUG/TEST(32444): Fragment_2 : onStart
07-22 07:10:00.297: DEBUG/TEST(32444): Activity_1 : onResume
07-22 07:10:00.297: DEBUG/TEST(32444): Fragment_2 : onResume
07-22 07:10:00.408: DEBUG/TEST(32444): Activity_2 : onStop
07-22 07:10:00.408: DEBUG/TEST(32444): Fragment_3 : onStop
07-22 07:10:00.408: DEBUG/TEST(32444): Activity_2 : onDestroy
07-22 07:10:00.408: DEBUG/TEST(32444): Fragment_3 : onDestroyView
07-22 07:10:00.408: DEBUG/TEST(32444): Fragment_3 : onDestroy
07-22 07:10:00.408: DEBUG/TEST(32444): Fragment_3 : onDetach

07-22 07:10:00.877: DEBUG/TEST(32444): Activity_1 : onBackPressed
07-22 07:10:00.877: DEBUG/TEST(32444): Fragment_2 : onPause
07-22 07:10:00.877: DEBUG/TEST(32444): Fragment_2 : onStop
07-22 07:10:00.877: DEBUG/TEST(32444): Fragment_2 : onDestroyView
07-22 07:10:00.887: DEBUG/TEST(32444): Fragment_2 : onDestroy
07-22 07:10:00.887: DEBUG/TEST(32444): Fragment_2 : onDetach
07-22 07:10:00.887: DEBUG/TEST(32444): Fragment_1 : onCreateView
07-22 07:10:00.897: DEBUG/TEST(32444): Fragment_1 : onActivityCreated
07-22 07:10:00.897: DEBUG/TEST(32444): Fragment_1 : onStart
07-22 07:10:00.897: DEBUG/TEST(32444): Fragment_1 : onResume

07-22 07:10:01.257: DEBUG/TEST(32444): Activity_1 : onBackPressed
07-22 07:10:01.267: DEBUG/TEST(32444): Activity_1 : onPause
07-22 07:10:01.267: DEBUG/TEST(32444): Fragment_1 : onPause
07-22 07:10:01.507: DEBUG/TEST(32444): Activity_1 : onStop
07-22 07:10:01.507: DEBUG/TEST(32444): Fragment_1 : onStop
07-22 07:10:01.507: DEBUG/TEST(32444): Activity_1 : onDestroy
07-22 07:10:01.517: DEBUG/TEST(32444): Fragment_1 : onDestroyView
07-22 07:10:01.517: DEBUG/TEST(32444): Fragment_1 : onDestroy
07-22 07:10:01.517: DEBUG/TEST(32444): Fragment_1 : onDetach




挙動は相当違うらしい。つづく。

2011/07/18

タブレットでFragmentを二つ表示したり消したり

タブレットでFragmentを増やしたり減らしたりする超簡単なサンプル。
画面を左右にわけ、左半分に表示されているFragment上のボタンを押すと右半分に新たなFragmentを表示させる。右Fragmentのボタンを押すと右Fragmentを一つ消す。左Fragmentのボタンを連打すると右Fragmentが多重に積み重なる。


main.xml (親ActivityのView)

・fragment.xml (FragmentのView)

・TestActivity (親Activity)

・Fragment1(画面左に最初から表示されているFragment)

・Fragment2 (画面右に表示するFragment)

Fragment ライフサイクルメモ

フラグメントのライフサイクルがイマイチ理解できなかったので、作ってみた。

Activity1・・・Fragment1
Activity2・・・Fragment2

Fragment1とFragment2にはそれぞれボタンが一つあり、Fragment1のボタンを押すとActivity2が起動・Fragment2が表示される。Fragment2のボタンを押すとActivity2のfinish()メソッドが実行されActivity1に戻る。Activity1に戻ったらBACKボタンを押してアプリを終了させる。


結果:
07-18 16:54:07.760: DEBUG/TEST(14499): Activity_1: onCreate
07-18 16:54:07.780: DEBUG/TEST(14499): Activity_1: onContentChanged
07-18 16:54:07.780: DEBUG/TEST(14499): Fragment_1: onAttach
07-18 16:54:07.780: DEBUG/TEST(14499): Activity_1: onAttachFragment
07-18 16:54:07.780: DEBUG/TEST(14499): Fragment_1: onCreate
07-18 16:54:07.780: DEBUG/TEST(14499): Activity_1: onStart
07-18 16:54:07.780: DEBUG/TEST(14499): Fragment_1: onCreateView
07-18 16:54:07.790: DEBUG/TEST(14499): Fragment_1: onActivityCreated
07-18 16:54:07.790: DEBUG/TEST(14499): Fragment_1: onStart
07-18 16:54:07.790: DEBUG/TEST(14499): Activity_1: onPostCreate
07-18 16:54:07.790: DEBUG/TEST(14499): Activity_1: onResume
07-18 16:54:07.790: DEBUG/TEST(14499): Fragment_1: onResume
07-18 16:54:07.790: DEBUG/TEST(14499): Activity_1: onPostResume
07-18 16:54:07.790: DEBUG/TEST(14499): Activity_1: onAttachedToWindow
07-18 16:54:07.800: DEBUG/TEST(14499): Activity_1: onCreateOptionsMenu


07-18 16:54:34.620: DEBUG/TEST(14499): Fragment_1: onClick
07-18 16:54:34.640: DEBUG/TEST(14499): Activity_1: onUserLeaveHint
07-18 16:54:34.640: DEBUG/TEST(14499): Fragment_1: onPause
07-18 16:54:34.640: DEBUG/TEST(14499): Activity_1: onPause
07-18 16:54:34.650: DEBUG/TEST(14499): Activity_2: onCreate
07-18 16:54:34.650: DEBUG/TEST(14499): Activity_2: onContentChanged
07-18 16:54:34.650: DEBUG/TEST(14499): Fragment_2: onAttach
07-18 16:54:34.650: DEBUG/TEST(14499): Activity_2: onAttachFragment
07-18 16:54:34.650: DEBUG/TEST(14499): Fragment_2: onCreate
07-18 16:54:34.650: DEBUG/TEST(14499): Activity_2: onStart
07-18 16:54:34.650: DEBUG/TEST(14499): Fragment_2: onCreateView
07-18 16:54:34.660: DEBUG/TEST(14499): Fragment_2: onActivityCreated
07-18 16:54:34.660: DEBUG/TEST(14499): Fragment_2: onStart
07-18 16:54:34.660: DEBUG/TEST(14499): Activity_2: onPostCreate
07-18 16:54:34.660: DEBUG/TEST(14499): Activity_2: onResume
07-18 16:54:34.660: DEBUG/TEST(14499): Fragment_2: onResume
07-18 16:54:34.660: DEBUG/TEST(14499): Activity_2: onPostResume
07-18 16:54:34.660: DEBUG/TEST(14499): Activity_2: onAttachedToWindow
07-18 16:54:34.680: DEBUG/TEST(14499): Activity_2: onCreateOptionsMenu
07-18 16:54:35.120: DEBUG/TEST(14499): Activity_1: onCreateDescription
07-18 16:54:35.120: DEBUG/TEST(14499): Activity_1: onSaveInstanceState
07-18 16:54:35.120: DEBUG/TEST(14499): Fragment_1: onSaveInstanceState
07-18 16:54:35.120: DEBUG/TEST(14499): Fragment_1: onStop
07-18 16:54:35.120: DEBUG/TEST(14499): Activity_1: onStop


07-18 16:54:58.010: DEBUG/TEST(14499): Fragment_2: onClick
07-18 16:54:58.030: DEBUG/TEST(14499): Fragment_2: onPause
07-18 16:54:58.030: DEBUG/TEST(14499): Activity_2: onPause
07-18 16:54:58.030: DEBUG/TEST(14499): Activity_1: onActivityResult
07-18 16:54:58.030: DEBUG/TEST(14499): Activity_1: onRestart
07-18 16:54:58.030: DEBUG/TEST(14499): Activity_1: onStart
07-18 16:54:58.030: DEBUG/TEST(14499): Fragment_1: onStart
07-18 16:54:58.030: DEBUG/TEST(14499): Activity_1: onResume
07-18 16:54:58.030: DEBUG/TEST(14499): Fragment_1: onResume
07-18 16:54:58.030: DEBUG/TEST(14499): Activity_1: onPostResume
07-18 16:54:58.330: DEBUG/TEST(14499): Fragment_2: onStop
07-18 16:54:58.330: DEBUG/TEST(14499): Activity_2: onStop
07-18 16:54:58.330: DEBUG/TEST(14499): Fragment_2: onDestroyView
07-18 16:54:58.330: DEBUG/TEST(14499): Fragment_2: onDestroy
07-18 16:54:58.330: DEBUG/TEST(14499): Fragment_2: onDetach
07-18 16:54:58.330: DEBUG/TEST(14499): Activity_2: onDestroy
07-18 16:54:58.330: DEBUG/TEST(14499): Activity_2: onDetachedFromWindow


07-18 16:55:28.440: DEBUG/TEST(14499): Activity_1: onBackPressed
07-18 16:55:28.450: DEBUG/TEST(14499): Fragment_1: onPause
07-18 16:55:28.450: DEBUG/TEST(14499): Activity_1: onPause
07-18 16:55:29.020: DEBUG/TEST(14499): Fragment_1: onStop
07-18 16:55:29.020: DEBUG/TEST(14499): Activity_1: onStop
07-18 16:55:29.020: DEBUG/TEST(14499): Fragment_1: onDestroyView
07-18 16:55:29.020: DEBUG/TEST(14499): Fragment_1: onDestroy
07-18 16:55:29.020: DEBUG/TEST(14499): Fragment_1: onDetach
07-18 16:55:29.020: DEBUG/TEST(14499): Activity_1: onDestroy
07-18 16:55:29.020: DEBUG/TEST(14499): Activity_1: onDetachedFromWindow

2011/07/04

ListViewやSpinnerを使ってみる2

ListViewに引き続き、Spinnerにデータを渡すAdapterの記事です。
ListView同様SpinnerでもSimpleAdapterとArrayAdapterが利用できます。
ただSpinnerで利用する際には

setDropDownViewResource

を呼ぶ必要があります。


Spinnerは画面に選択された値が出ている時と、それをクリックしてダイアログが飛び出てくる時(ドロップダウン時)と、2種類のViewを持っているためsetDropDownViewResourceを指定して飛び出してきた際のViewを指定しましょう。
まぁ別に、「画面にいるときも飛び出してきたときも同じViewで問題無い」って場合は呼ぶ必要無いんですが。。。

ただしArrayAdapterやSimpleAdapterを利用する場合、通常のViewとドロップダウン時のビューで指定するレイアウト上のID(≠レイアウトxmlのID)を同一にする必要がある様です。


今回はArrayAdapterの場合のみ。
レイアウトxmlはAndroidに標準で用意された物を利用します。



ListViewとの違いはドロップダウン時のViewを指定することと、選択時のリスナー名が違うことくらいです。


次はListViewの内容を更にカスタマイズ。

ListViewやSpinnerを使ってみる1

今回はListViewやSpinnerに表示する項目にデータを渡すAdapterに関する記事です。

AndroidでListViewやSpinnerを利用するには標準でSimpleAdapterやArrayAdapter(他にもCursorAdapter等)が用意されています。そしてこれらAdapterはBaseAdapterというものを継承して作成されています。

とりあえずはSimpleAdapterとArrayAdapterについて簡単に解説します。

まずSimpleAdapterとArrayAdapterについて違う部分を先に説明すると、前者は渡すデータがMap<String, ?>で後者がStringやCharSequenceになります。また前者は渡した後のデータをAdapter内で変更することが出来ませんが、後者は足したり引いたりソートしたり出来ます。



まずはSimpleAdapterについて
SimpleAdapterのコンストラクターでは
  • 内包するMapデータ
  • ListViewで表示するレイアウトxml
  • Mapデータのキーと対応するレイアウトのID
を渡す必要があります。

表示できる内容はTextView、CheckedTextView、ImageView、CheckBox?
ImageViewに表示できる内容はリソースIDを渡せる画像のみです。
私自身はこの記事を書いている時点でアプリにSimpleAdapterを利用したことがありません。

そんな私が作ったSimpleAdapterのサンプルコードです。
レイアウトXML(simpleadapter_layout1.xml)





次にArrayAdapterの簡単な使い方です。
ArrayAdapterでは基本的に1つのTextView(CheckedTextView)だけを表示することが出来ます。
コンストラクターは
  • 内包するテキストデータ
  • ListViewで表示するレイアウトxml
  • レイアウトxml上のTextViewのID
を渡す必要があります。
私自身はこの記事を書いている時点でアプリにArrayAdapterを利用したことがありません。

レイアウトxml(arrayadapter_layout1.xml)





おまけ
SimpleAdapterで内容を動的に変えてみる場合。
Adapterと同期するData(SimpleAdapterの場合はList<Map>)を別に管理することで、中身の追加・削除が容易に行えます。

(レイアウトxmlは上のSimpleAdapter例と同じ)



ListViewは覚えてしまえば非常に簡単で使いやすいと思います。
次回は適度にSpinnerについて。