android:launchModeとonNewIntentメソッドについてメモ。
android:launchMode
http://bit.ly/cuooyE
onNewIntent
http://bit.ly/g8n7QT
以下、やりたかったこと。
(1)自分のアプリのメインActivity(入力欄を持っている)からブラウザを起動。
(2)ブラウザのURL共有機能で上記のActivityを呼ぶ。
(3)この時、ブラウザ起動前に入力された内容が消滅しないこと。
(4)入力欄に共有URLをappendする。
android:launchModeにsingleTaskを指定すると(3)は実現できました。
デフォルトのstandardだとダメだったということです。
でも、それだけだと共有URL情報を持ったIntentを受け取れませんでした。
つまり、(4)が実現できませんでした。
なので、onNewIntentメソッドをOverrideしつつ書きました。
これで(4)も実現できました。
@Override
protected void onNewIntent(Intent intent) {
// TODO
}
伴い、以下の問題が発生しました。
(1)自分のアプリのメインActivity以外のActivityを表示する。
(2)homeボタン長押しで他のアプリを起動する。
(3)homeボタン長押しで自分のアプリを起動する。
(4)自分のアプリはメインActivityが表示される。
android:launchModeを書いていなかった時(すなわちデフォルトのstandardだっだ場合)は
(4)のタイミングで(1)のActivityが表示されていました。
ちなみにandroid:launchModeをsingleInstanceにしてみたところ、
やりたかったことも上記の問題も発生はしませんでした。
ただ、WebViewが正しく表示されなくなってしまいました。
コレはさすがに致命的だったので、とりあえずsingleTaskにしています。
2013年4月26日金曜日
アクティビティとタスク
「開発の基礎」の「アクティビティとタスク」の節がなかなか理解できなかったのでまとめ。
タスク
アクティビティのスタック。ブラウザでいえばHistoryみたいなもの。タスクそれぞれにアクティビティのスタックがある。
タスクはブラウザのタブみたいなもの。ただし、タブのように "見える化" されていなくてタスクに含まれるアプリケーションを再び起動しようとしたときにそのアプリケーションのタスクがフォアグラウンドになる。ただし、インテントのflagプロパティやアクティビティの起動モード定義によって挙動は変わる。
Affinity (親和性?)
アクティビティは自身と同じAffinityが設定されているタスクに所属しようとする。
タスクのAffinityはルートのアクティビティによって決まる。
アクティビティのAffinityはAndroidManifest.xmlのactivity要素のtaskAffinity属性で設定(たぶん任意の文字列で指定可能)。指定がなければ、application要素のtaskAffinity属性を継承する。アプリケーションのAffinityのデフォルトはmanifest要素のパッケージ名。
インテントにFLAG_ACTIVITY_NEW_TASK フラグが設定されている場合、新しいアクティビティは別のタスクに所属しようとするが、そのアクティビティと同じAffinityが設定されている既存のタスクがあればそこに追加される。なければ新しいタスクが開始される。
[あとで検証] もしFLAG_ACTIVITY_NEW_TASK フラグを設定したインテントで新しいアクティビティを起動するとき、startActivity()を呼び出したタスクと新しいアクティビティに同じAffinityが設定されていたら新しいタスクが起動するかどうか。たぶん新しいタスクはできないと予想。
activity要素に allowTaskReparenting="true" と設定されていると、このアクティビティと同じAffinityが設定されているタスクがフォアグラウンドに移ったときに、アクティビティを開始したタスクからそのタスクに移動できる。たとえば taskAffinity="A" のタスクで taskAffinity="B" のアクティビティを開始すると B は A のタスクに属するが、taskAffinity="B" のアプリケーションを起動すると B のアクティビティがこのタスクに移動する。
起動モード
activity要素の launchMode属性で定義。
"standard"
インテントを開始した(startActivity() を呼び出した)タスクに保持される。
複数回インスタンス化できる。
新しいインテントに応答するときには必ず新しいインスタンスが作成される。
"singleTop"
インテントを開始した(startActivity() を呼び出した)タスクに保持される。
複数回インスタンス化できる。
既存のインスタンスがスタックの最上位にあれば再利用して新しいインテントを処理する。最上位にない場合は新しいインスタンスが作成される。
"singleTask"
アクティビティが常にタスクのルート アクティビティになる。
アクティビティのインスタンスは1つに制限される。
同じタスクに属する別のアクティビティを開始することができる。
このアクティビティがスタックの最上位にない場合インテントはドロップされる。インテントがドロップされたとしても、タスクがフォアグラウンドに移ったままになる。
"singleInstance"
アクティビティが常にタスクのルート アクティビティになる。
アクティビティのインスタンスは1つに制限される。
そのタスク内の唯一のアクティビティとして単独で動作。ここから別のアクティビティを開始した場合、そのアクティビティは別のタスクで起動する。
後述するが、アプリケーションのメインアクティビティには singleTask が向いているはずだが、実際は上記のような挙動にならないため standard に設定しておくと良い。
スタックのクリア
ユーザーがタスクを長時間放置したときは、ルート以外のアクティビティがクリアされる。この挙動はactivity要素の属性で変更できる。
alwaysRetainTaskState = "true"
アクティビティはクリアされない。
clearTaskOnLaunch = "true"
タスクを離れるとルートを含めた全てのアクティビティがクリアされる。
finishOnTaskLaunch = "true"
タスクを離れるとこのアクティビティはクリアされる。それがルートであっても。
Intent に FLAG_ACTIVITY_CLEAR_TOP フラグを設定すると、インテントを処理するアクティビティのインスタンスが対象タスクのスタック内に存在する場合、そのインスタンスより上位(新しい方)のアクティビティはすべてクリアされる。
startActivityForResult() で呼び出したアクティビティがクリアされてしまった場合、呼び出し元アクティビティの onActivityResult() が resultCode = RESULT_CANCELED で呼ばれる。
タスクの開始
アクティビティのインテントフィルタのアクションを android.intent.action.MAIN、カテゴリを android.intent.category.LAUNCHER に設定すると、アクティビティのアイコンとラベルがアプリケーションランチャに表示され、アプリケーションのエントリポイントになる。
ドキュメントでは、この設定をしたアクティビティはユーザーが他のタスクに移動したあとでアプリケーションに戻ってこられるように、起動モード singleTask か singleInstance を設定したほうが良いとされているが、実際にやってみると起動モード singleTask ではルートアクティビティ以外がクリアされた状態で起動してしまう。なぜか起動モード standard のタスクではスタックが保持されたまま元のタスクに戻ることができた。
タスク
アクティビティのスタック。ブラウザでいえばHistoryみたいなもの。タスクそれぞれにアクティビティのスタックがある。
タスクはブラウザのタブみたいなもの。ただし、タブのように "見える化" されていなくてタスクに含まれるアプリケーションを再び起動しようとしたときにそのアプリケーションのタスクがフォアグラウンドになる。ただし、インテントのflagプロパティやアクティビティの起動モード定義によって挙動は変わる。
Affinity (親和性?)
アクティビティは自身と同じAffinityが設定されているタスクに所属しようとする。
タスクのAffinityはルートのアクティビティによって決まる。
アクティビティのAffinityはAndroidManifest.xmlのactivity要素のtaskAffinity属性で設定(たぶん任意の文字列で指定可能)。指定がなければ、application要素のtaskAffinity属性を継承する。アプリケーションのAffinityのデフォルトはmanifest要素のパッケージ名。
インテントにFLAG_ACTIVITY_NEW_TASK フラグが設定されている場合、新しいアクティビティは別のタスクに所属しようとするが、そのアクティビティと同じAffinityが設定されている既存のタスクがあればそこに追加される。なければ新しいタスクが開始される。
[あとで検証] もしFLAG_ACTIVITY_NEW_TASK フラグを設定したインテントで新しいアクティビティを起動するとき、startActivity()を呼び出したタスクと新しいアクティビティに同じAffinityが設定されていたら新しいタスクが起動するかどうか。たぶん新しいタスクはできないと予想。
activity要素に allowTaskReparenting="true" と設定されていると、このアクティビティと同じAffinityが設定されているタスクがフォアグラウンドに移ったときに、アクティビティを開始したタスクからそのタスクに移動できる。たとえば taskAffinity="A" のタスクで taskAffinity="B" のアクティビティを開始すると B は A のタスクに属するが、taskAffinity="B" のアプリケーションを起動すると B のアクティビティがこのタスクに移動する。
起動モード
activity要素の launchMode属性で定義。
"standard"
インテントを開始した(startActivity() を呼び出した)タスクに保持される。
複数回インスタンス化できる。
新しいインテントに応答するときには必ず新しいインスタンスが作成される。
"singleTop"
インテントを開始した(startActivity() を呼び出した)タスクに保持される。
複数回インスタンス化できる。
既存のインスタンスがスタックの最上位にあれば再利用して新しいインテントを処理する。最上位にない場合は新しいインスタンスが作成される。
"singleTask"
アクティビティが常にタスクのルート アクティビティになる。
アクティビティのインスタンスは1つに制限される。
同じタスクに属する別のアクティビティを開始することができる。
このアクティビティがスタックの最上位にない場合インテントはドロップされる。インテントがドロップされたとしても、タスクがフォアグラウンドに移ったままになる。
"singleInstance"
アクティビティが常にタスクのルート アクティビティになる。
アクティビティのインスタンスは1つに制限される。
そのタスク内の唯一のアクティビティとして単独で動作。ここから別のアクティビティを開始した場合、そのアクティビティは別のタスクで起動する。
後述するが、アプリケーションのメインアクティビティには singleTask が向いているはずだが、実際は上記のような挙動にならないため standard に設定しておくと良い。
スタックのクリア
ユーザーがタスクを長時間放置したときは、ルート以外のアクティビティがクリアされる。この挙動はactivity要素の属性で変更できる。
alwaysRetainTaskState = "true"
アクティビティはクリアされない。
clearTaskOnLaunch = "true"
タスクを離れるとルートを含めた全てのアクティビティがクリアされる。
finishOnTaskLaunch = "true"
タスクを離れるとこのアクティビティはクリアされる。それがルートであっても。
Intent に FLAG_ACTIVITY_CLEAR_TOP フラグを設定すると、インテントを処理するアクティビティのインスタンスが対象タスクのスタック内に存在する場合、そのインスタンスより上位(新しい方)のアクティビティはすべてクリアされる。
startActivityForResult() で呼び出したアクティビティがクリアされてしまった場合、呼び出し元アクティビティの onActivityResult() が resultCode = RESULT_CANCELED で呼ばれる。
タスクの開始
アクティビティのインテントフィルタのアクションを android.intent.action.MAIN、カテゴリを android.intent.category.LAUNCHER に設定すると、アクティビティのアイコンとラベルがアプリケーションランチャに表示され、アプリケーションのエントリポイントになる。
ドキュメントでは、この設定をしたアクティビティはユーザーが他のタスクに移動したあとでアプリケーションに戻ってこられるように、起動モード singleTask か singleInstance を設定したほうが良いとされているが、実際にやってみると起動モード singleTask ではルートアクティビティ以外がクリアされた状態で起動してしまう。なぜか起動モード standard のタスクではスタックが保持されたまま元のタスクに戻ることができた。
登録:
投稿 (Atom)