今日のトピックに関する理論全体は、 developer.android.com /guide/topics/manifest/activity-element.htmlにあります。いくつかの場所でそれを参照し、実際にどのように機能するかを理解し、どのような状況でそれを見つけようとします実際に使用できます。
AndroidManifestとコード内のIntentフラグの両方で、いくつかのパラメーターを追加できます。
intent.setFlags(Intent.FLAG_ACTIVITY_*);
android:launchMode
パラメータは、特定のアクティビティへの呼び出しで新しいインテントをアクティブにしたときに何が起こるかを決定します。
この例では、ActivityAに適用されます。
「標準」および「シングルトップ」(FLAG_ACTIVITY_SINGLE_TOP)
"standard"
がデフォルトの動作です。 システムは常に新しいアクティビティを作成し、スタックの一番上に追加します。
ActivityAを変更して、ActivityBに切り替えるのではなく、自動的に起動するようにします。
( "標準") A-> A->戻る->戻る:
*** *** INFO/ActivityManager(249): START {flg=0x10000000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 28371 INFO/ActivityManager(249): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityA: pid=28410 uid=10060 gids={1028} DEBUG/ActivityA(28410): onCreate() DEBUG/ActivityA(28410): onStart() INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +2s64ms *** ActivityA *** INFO/ActivityManager(249): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 28410 DEBUG/ActivityA(28410): onCreate() DEBUG/ActivityA(28410): onStart() INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +739ms DEBUG/ActivityA(28410): onStop() *** back *** DEBUG/ActivityA(28410): onStart() DEBUG/ActivityA(28410): onStop() DEBUG/ActivityA(28410): onDestroy() *** back *** DEBUG/ActivityA(28410): onStop() DEBUG/ActivityA(28410): onDestroy() *** Home screen***
スタックには2つの同一のアクティビティがあり、2回のバッククリック後にプロセスが終了したことがわかります。
"singleTop"
は、再度呼び出されたときにスタックの最上部にあるアクティビティの重複を防ぎます。
( "SingleTop") A-> A->戻る:
*** *** INFO/ActivityManager(249): START {flg=0x10000000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 31016 INFO/ActivityManager(249): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityA: pid=31070 uid=10060 gids={1028} DEBUG/ActivityA(31070): onCreate() DEBUG/ActivityA(31070): onStart() INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +1s296ms *** ActivityA *** INFO/ActivityManager(249): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 31070 DEBUG/ActivityA(31070): onNewIntent() *** back *** DEBUG/ActivityA(31070): onStop() DEBUG/ActivityA(31070): onDestroy() *** Home screen***
新しいアクティビティは作成されず、代わりに
onNewIntent()
呼び出しがありました。 最初のバックでは、アプリケーションを離れました。
「SingleTask」および「singleInstance」
"singleTask"
および
"singleInstance"
は、同じアクティビティの複数のエンティティを許可しません。 これらは、タスクで他のアクティビティを使用する能力が異なります。
( "SingleTask") A-> B-> C-> A->戻る:
*** *** INFO/ActivityManager(249): START {flg=0x10000000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 1496 INFO/ActivityManager(249): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityA: pid=1529 uid=10060 gids={1028} DEBUG/ActivityA(1529): onCreate() DEBUG/ActivityA(1529): onStart() INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +1s769ms *** ActivityB *** INFO/ActivityManager(249): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityB u=0} from pid 1529 DEBUG/ActivityB(1529): onCreate() DEBUG/ActivityB(1529): onStart() INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityB: +524ms DEBUG/ActivityA(1529): onStop() *** ActivityC *** INFO/ActivityManager(249): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityC u=0} from pid 1529 DEBUG/ActivityC(1529): onCreate() DEBUG/ActivityC(1529): onStart() INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityC: +267ms DEBUG/ActivityB(1529): onStop() *** ActivityA *** DEBUG/ActivityB(1529): onDestroy() DEBUG/ActivityA(1529): onNewIntent() DEBUG/ActivityA(1529): onStart() DEBUG/ActivityC(1529): onStop() DEBUG/ActivityC(1529): onDestroy() *** back *** 11-13 00:08:00.039: DEBUG/ActivityA(1529): onStop() 11-13 00:08:00.039: DEBUG/ActivityA(1529): onDestroy() *** Home screen***
再びActivityAに切り替えると、システムはスタック内でその上にあったすべてのアクティビティを破棄しました。 押すとホーム画面に戻ります。
( "SingleInstance") A-> B-> C-> A-> back-> back-> back:
*** *** 11-13 00:12:27.132: INFO/ActivityManager(249): START {flg=0x10000000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 2418 11-13 00:12:27.859: INFO/ActivityManager(249): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityA: pid=2438 uid=10060 gids={1028} 11-13 00:12:28.332: DEBUG/ActivityA(2438): onCreate() 11-13 00:12:28.457: DEBUG/ActivityA(2438): onStart() 11-13 00:12:29.254: INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +1s606ms *** ActivityB *** 11-13 00:12:32.195: INFO/ActivityManager(249): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityB u=0} from pid 2438 11-13 00:12:32.679: DEBUG/ActivityB(2438): onCreate() 11-13 00:12:32.824: DEBUG/ActivityB(2438): onStart() 11-13 00:12:33.394: INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityB: +897ms 11-13 00:12:33.547: DEBUG/ActivityA(2438): onStop() *** ActivityC *** 11-13 00:12:36.257: INFO/ActivityManager(249): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityC u=0} from pid 2438 11-13 00:12:36.507: DEBUG/ActivityC(2438): onCreate() 11-13 00:12:36.582: DEBUG/ActivityC(2438): onStart() 11-13 00:12:37.343: INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityC: +989ms 11-13 00:12:37.695: DEBUG/ActivityB(2438): onStop() *** ActivityA *** 11-13 00:12:38.660: INFO/ActivityManager(249): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 2438 11-13 00:12:38.734: DEBUG/ActivityA(2438): onNewIntent() 11-13 00:12:38.734: DEBUG/ActivityA(2438): onStart() 11-13 00:12:39.789: DEBUG/ActivityC(2438): onStop() *** back *** 11-13 00:12:41.425: DEBUG/ActivityC(2438): onStart() 11-13 00:12:42.250: DEBUG/ActivityA(2438): onStop() 11-13 00:12:42.250: DEBUG/ActivityA(2438): onDestroy() *** back *** 11-13 00:12:52.332: DEBUG/ActivityB(2438): onStart() 11-13 00:12:52.894: DEBUG/ActivityC(2438): onStop() 11-13 00:12:52.898: DEBUG/ActivityC(2438): onDestroy() *** back *** 11-13 00:12:55.617: DEBUG/ActivityB(2438): onStop() 11-13 00:12:55.617: DEBUG/ActivityB(2438): onDestroy() *** Home screen***
ActivityAに切り替えてもチェーンリアクションはトリガーされませんでしたが、1つのActivityAで別のタスクが開かれました。 戻るの最初のプレスで完成しました。 さらに2回クリックするだけで、ホーム画面に入ることができます。 唯一のエンティティActivityAは上で破壊され、そこへの戻りはありませんでした。 外部的には、ActivityAからActivityBへ、およびActivityCからActivityAへの移行(つまり、同じプロセス内の異なるタスク間の移行)は、アプリケーションの変更、つまり 1つのアクティビティを折りたたみ、よりスムーズな遷移ではなく、新しいアクティビティから飛び出します。
android:noHistory(FLAG_ACTIVITY_NO_HISTORY)
デフォルト値は
false
です。
true
場合、停止したアクティビティに戻ることはできません。
パラメーターは、値
true
ActivityAに適用され
true
。
<activity android:name=".ActivityA" android:noHistory="true">
A-> B->戻る:
*** *** INFO/ActivityManager(249): START {flg=0x10000000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 4875 INFO/ActivityManager(249): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityA: pid=4915 uid=10060 gids={1028} DEBUG/ActivityA(4915): onCreate() DEBUG/ActivityA(4915): onStart() INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +1s383ms *** ActivityB *** INFO/ActivityManager(249): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityB u=0} from pid 4915 DEBUG/ActivityB(4915): onCreate() DEBUG/ActivityB(4915): onStart() INFO/ActivityManager(249): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityB: +877ms DEBUG/ActivityA(4915): onStop() *** back *** DEBUG/ActivityA(4915): onDestroy() DEBUG/ActivityB(4915): onStop() DEBUG/ActivityB(4915): onDestroy() *** Home screen***
onDestroy()
ActivityAで起動された瞬間から判断すると、ActivityAが呼び出された後でもメモリに残っていました。
onStop()
。ただし、そこに戻ることはできなくなりました。
このパラメーターは、アプリケーションの起動時にロゴを表示する必要があり、そのロゴに戻らない場合に使用すると便利です。
android:clearTaskOnLaunch and android:finishOnTaskLaunch
clearTaskOnLaunch
パラメーター
clearTaskOnLaunch
、
true
場合、アプリケーションの再起動時に、スタック(または特定のタスク)上のすべての非ルートアクティビティを破棄するようシステムに
clearTaskOnLaunch
ます。 ルートアクティビティのみに適用するのは理にかなっているため、ログの取得元の例では、ActivityAに追加しました。
<activity android:name=".ActivityA" android:clearTaskOnLaunch="true">
アプリの開始-> A-> B-> C->ホーム->アプリの開始:
*** *** INFO/ActivityManager(250): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 476 DEBUG/ActivityA(3412): onCreate() DEBUG/ActivityA(3412): onStart() INFO/ActivityManager(250): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +295ms *** ActivityB *** INFO/ActivityManager(250): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityB u=0} from pid 3412 DEBUG/ActivityB(3412): onCreate() DEBUG/ActivityB(3412): onStart() INFO/ActivityManager(250): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityB: +140ms DEBUG/ActivityA(3412): onStop() *** ActivityC *** INFO/ActivityManager(250): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityC u=0} from pid 3412 DEBUG/ActivityC(3412): onCreate() DEBUG/ActivityC(3412): onStart() INFO/ActivityManager(250): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityC: +131ms DEBUG/ActivityB(3412): onStop() *** Home *** INFO/ActivityManager(250): START {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.android.launcher/com.android.launcher2.Launcher u=0} from pid 250 DEBUG/ActivityC(3412): onStop() *** *** INFO/ActivityManager(250): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 476 DEBUG/ActivityC(3412): onDestroy() DEBUG/ActivityB(3412): onDestroy() DEBUG/ActivityA(3412): onStart()
アプリケーションを再起動すると、Androidが子ActivityBとActivityCをメモリから破壊したことがわかります。 また、Recentsメニュー(ホームボタンを長押し)からアプリケーションに戻ってもIntent LAUNCHERが開始されないため、ActivityCに戻ることになります。
finishTaskOnLaunch
パラメーターを使用して、
finishTaskOnLaunch
同じ動作を実現できます。 このパラメーターの値が
true
であるアプリケーションを再起動すると、Androidはこれらのアクティビティを破棄し
true
。 つまり この例では、同じログを表示するには、ActivityBとActivityCに登録するだけで十分です。
<activity android:name=".ActivityB" android:finishOnTaskLaunch="true"/> <activity android:name=".ActivityC" android:finishOnTaskLaunch="true"/>
デフォルトでは、両方のパラメーターは
false
です。
考えられる使用例の1つは、
excludeFromRecents
パラメーター(RecentsメニューにActivityを含まない)と組み合わせて、停止したActivityに戻れないことを実現することです。 しかし、もっと具体的な、または逆に単純なケースがあると思います。
android:parentActivityName
このパラメーターを使用すると、特定のアクティビティの親を必要に応じて作成できます。 ただし、戻るボタンではなく、ナビゲーションアップ(http://developer.android.com/training/implementing-navigation/ancestral.html)によって、たとえばアクションバーのように、そこに戻ることに注意してください。 。 しかし、気にしないために、ActivityCで
onBackPressed()
を再定義し、ActivityAをActivityCの親にします。
例:
@Override public void onBackPressed() { onNavigateUp(); }
<activity android:name=".ActivityC" android:parentActivityName=".ActivityA"> <!-- Parent activity meta-data to support 4.0 and lower --> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".ActivityA" /> </activity>
A-> B-> C->戻る:
*** *** INFO/ActivityManager(250): START {flg=0x10000000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 6620 INFO/ActivityManager(250): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityA: pid=6634 uid=10060 gids={1028} DEBUG/ActivityA(6634): onCreate() DEBUG/ActivityA(6634): onStart() INFO/ActivityManager(250): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +895ms *** ActivityB *** INFO/ActivityManager(250): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityB u=0} from pid 6634 DEBUG/ActivityB(6634): onCreate() DEBUG/ActivityB(6634): onStart() INFO/ActivityManager(250): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityB: +179ms DEBUG/ActivityA(6634): onStop() *** ActivityC *** INFO/ActivityManager(250): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityC u=0} from pid 6634 DEBUG/ActivityC(6634): onCreate() DEBUG/ActivityC(6634): onStart() INFO/ActivityManager(250): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityC: +144ms DEBUG/ActivityB(6634): onStop() *** back *** INFO/ActivityManager(250): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 6634 DEBUG/ActivityB(6634): onDestroy() DEBUG/ActivityA(6634): onDestroy() DEBUG/ActivityA(6634): onCreate() DEBUG/ActivityA(6634): onStart() INFO/ActivityManager(250): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +182ms DEBUG/ActivityC(6634): onStop() DEBUG/ActivityC(6634): onDestroy()
クリックして戻ると、予想以上のことが起こったことがわかります。 破壊されたのは親の上にあったアクティビティだけではなく、彼女自身も再現されました。 ただし、全体的には動作が予想されます。
ユーザーが、たとえば戻るボタンに何度も戻ることなく子アクティビティについて長い間さまよい歩いた後、メインメニューに戻ることができるようにするために使用するのが合理的です(予想どおり、アクションバーで実装する場合)。
android:allowTaskReparenting and android:taskAffinity
allowTaskReparenting
パラメーターを
allowTaskReparenting
と、タスク#2で以前に作成された(つまり、それに関連付けられている)タスク#1から呼び出されたアクティビティをタスク#1にバインド
allowTaskReparenting
。
準備:
<activity android:name=".ActivityA" android:launchMode="singleInstance" > <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".ActivityB" android:launchMode="singleTask" /> <activity android:name=".ActivityC" android:launchMode="singleTask" android:allowTaskReparenting="true" android:taskAffinity=".ActivityA" />
ActivityCを開始するボタンをActivityAフォームにもう1つ追加します。
マニフェストファイルでは、ActivityAが親であると主張する場合、ActivityCが親を変更することを許可しました。
アプリの開始-> A-> B-> C->ホーム->アプリの開始-> A-> C->戻る:
*** *** INFO/ActivityManager(250): START {flg=0x10000000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 10495 INFO/ActivityManager(250): Start proc com.habrahabr.ActivityStackLifeCycle for activity com.habrahabr.ActivityStackLifeCycle/.ActivityA: pid=10524 uid=10060 gids={1028} DEBUG/ActivityA(10524): onCreate() DEBUG/ActivityA(10524): onStart() INFO/ActivityManager(250): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityA: +761ms *** ActivityB *** INFO/ActivityManager(250): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityB u=0} from pid 10524 DEBUG/ActivityB(10524): onCreate() DEBUG/ActivityB(10524): onStart() INFO/ActivityManager(250): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityB: +225ms DEBUG/ActivityA(10524): onStop() *** ActivityC *** INFO/ActivityManager(250): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityC u=0} from pid 10524 DEBUG/ActivityC(10524): onCreate() DEBUG/ActivityC(10524): onStart() INFO/ActivityManager(250): Displayed com.habrahabr.ActivityStackLifeCycle/.ActivityC: +204ms DEBUG/ActivityB(10524): onStop() *** Home*** INFO/ActivityManager(250): START {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.android.launcher/com.android.launcher2.Launcher u=0} from pid 250 DEBUG/ActivityC(10524): onStop() *** *** INFO/ActivityManager(250): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityA u=0} from pid 476 DEBUG/ActivityA(10524): onNewIntent() DEBUG/ActivityA(10524): onStart() *** ActivityC *** INFO/ActivityManager(250): START {cmp=com.habrahabr.ActivityStackLifeCycle/.ActivityC u=0} from pid 10524 DEBUG/ActivityC(10524): onNewIntent() DEBUG/ActivityC(10524): onStart() DEBUG/ActivityA(10524): onStop() *** back *** DEBUG/ActivityA(10524): onStart() DEBUG/ActivityC(10524): onStop() DEBUG/ActivityC(10524): onDestroy()
Homeを押す前に、Task1 [A]、Task2 [B、C]という2つのエンティティがありました。 アプリケーションを再起動した後、ActivityAからActivityC、つまり さらに、
allowTaskReparenting
と
taskAffinity
いない
allowTaskReparenting
、
taskAffinity
別のアプリケーションとして動作し、押し戻すとルートActivityBに戻ります。 オプションのおかげで、戻るボタンはTask1に戻りました。
実際には、このような複雑な作業スキームを1つのアプリケーション内に構築する必要はめったにありません。したがって、タスク1とタスク2のサイトに別々のアプリケーションを表示し、一方が他方のアクティビティを呼び出して短いタスクを実行し、押し戻してからデバイス画面を制御します。
android:alwaysRetainTaskState
デフォルトでは、ユーザーがアクセスしていない場合、システムは一定時間(「30分」など)©developer.android.comの後、アクティビティとともにタスクを破棄します。 Activityパラメーター
alwaysRetainTaskState
を
true
設定することにより、それらは永久に存続させることができます(メモリー不足の場合を除く)。 これは理論的に説明されており、ここでキャッチを想像するのは難しいので、テストは行いませんでした。
追加 :まだ問題があることが判明した。ara89のコメントに感謝。 Android 4.0(APIレベル14)以降、アクティビティの破棄が停止し、このパラメーターは使用できなくなりました。 ここで2.3.7と4.0.1の差分を確認できます (
ACTIVITY_INACTIVE_RESET_TIME
フィールドに注意してください)。 ただし、Androidトラッカーでこれに対してバグが作成されましたが、まだ新しいステータスであり、所有者はいません。
アクティビティスタックのライフサイクル(パート1)