この前、盛大に勘違いしてることがあったので、調べ直して挙動の違いをまとめました。
launchModeはAndroidManifest.xmlにActivityごとに設定でき、Activityの起動方法を指定しします。
standard (default)
デフォルトのlaunchModeです。指定しない場合はstandardになります。
Activityが開始されるたびにスタックに積まれていきます。
バックキー等でActivityが終了するときに、最後に積まれたActivityから順番に取り除かれていきます。
もし、同じActivityを起動した場合は別のインスタンスとなり、通常通りスタックに積まれます。連続して起動した場合も同様です。
singleTop
対象のActivityが一番上にある状態で、同じActivityを起動したときに、新しくインスタンスを作らず、 onNewIntent
を呼び出す処理になります。スタックに新しく積まれません。
例として、Activity BをsingleTopにします。
Activity Bが一番上にある状態で再びActivity Bを起動したときは、インスタンスが作られず、元々あるActivity BのonNewIntentが呼びされます。
一番上に対象のActivityがない場合は、通常通り別のインスタンスが作成され、スタックに積まれます。
singleTask
すでに対象のActivityがある場合は、そのインスタンスが再度利用され(onNewIntent
が呼ばれる)、さらにそれまでスタックに積まれているActivityを破棄します。
Activity BをsingleTaskにします。
以下の右側の状態から、Activity Bを起動した場合はBの上にあったCとDが破棄され、Activityが一番上の状態になります。CとDはonDestroyが呼び出されます。
taskAffinity
更にsingleTaskはtaskAffinityに指定して挙動を変更することができます。
taskAffinityは雑に説明すると、別のタスクを指定するために識別子になります。通常、同じアプリケーションのAtivityは同じタスクに属することになります。taskAffinityを指定することで、別のタスクでActivityを起動することが可能になります。
Activity BにtaskAffinityを設定してみます。
このときに、Activity Bを起動すると新しくタスクが作成され、そこにActivity Bのスタックが積まれます。
このときアプリの履歴を表示すると、以下のように別のアプリのように見えます。
このときにAからCを起動する、Task1のほうにスタックは積まれ、BのほうからCを起動するとTask2のほうにスタックが積まれるという状態が可能になります。
singleInstance
最後にsingleInstanceです。singleInstanceはだいぶ特殊な感じの挙動をします。singleInstanceに指定されたActivityは別のタスクで起動され、さらにそのタスクでは、指定されたActivityのみが存在することになります。
Activity Bを起動したときは、別のタスクで起動されます。これは先程のsingleTaskとtaskAffinityを指定した挙動と同じです。
この状態で、Activity BからActivity Cを起動するとTask1のほうで起動されActivity Aの上に積まれます。Task2のほうではActivity Bしか存在しない状態になります。
この状態で、さらにActivity Bを呼び出した場合は、タスクが切り替わるのみで新しくActivity Bのインスタンスが作られず、既存のonNewIntentが呼び出されるだけになります。
分かりにくいかもしれませんが、画面の動きは次のようになります。
以下はA -> B -> Cの順で起動しています。アプリが切り替わってるような動きになっています。
更に、先程の状態からバックキーを押して戻ると、次のような画面の動きになります。