launch Modeとは
文字通り、Activityの起動方法を指す。
具体的には4つのモードがあり、分け方としてはyanzm先生のブログによると
- intentに応対するActivityがどのタスクに保持されるか
- Activityのインスタンスを複数生成できるか
- インスタンスのタスクに他のActivityを含めることはできるのか
- クラスの新しいインスタンスを起動して新しいインスタンスを処理するかどうか
といった軸で分類されているとのこと。わかりやすい表が記載されていて、それぞれ詳しく説明されているのでここでは割愛。
以下ではlaunch Modeを考える上で必要な「スタックとタスク」について簡単に示したうえで、launch Modeをdefault以外に設定する場合のユースケースについてざっくりと説明する。
スタックとタスク
スタックとはリスト構造のうち挿入と削除がリストの先頭からしかできないものを指す。
通常、AndroidManifest.xmlでaction.Mainで指定されたActivityがHome画面から呼ばれて最初に表示される。そのActivityをAとすると、AからstarActivity()を呼ぶことで別のActivity Bを生成し、A -> Bへの画面遷移が生じる。このとき、AがスタックにpushされてonStop()が呼び出される。Bが表示された状態からバックボタンを押すと、Bはfinish()されるのでAが再び前面に出てくる。
タスクとは簡単にいうと"Activityのまとまり"を指す。なにも設定をいじらずにひたすらstartActivity()をした場合、1つのアプリの持つタスクは1つとなる。つまり複数アプリを起動させているときは、アプリの数だけタスクを持ち、その中に複数のActivityからなるスタックが形成されている。
つまり、Activityもタスクも、スタックを形成する。
詳細
まずは4種類のモードについて
こちらに書いてあることを簡潔に説明すると、
-
standard(通常): デフォルトのモードで、複数のインスタンスを生成できる。各インスタンスを異なるタスクに所属させることも、ひとつのタスクが複数のインスタンスを保持することも可能となる。
-
singleTop(便利):スタックのトップにあるActivityに対してintentを呼び出した時、activityのインスタンスは生成されず、onNewIntent()が呼ばれ使い回される。トップ以外にある場合はstandardと同様に作動する。
-
singleTask(特殊):そのActivityのインスタンスが存在しない場合は、新しいタスクにActivityが生成されそこにintentが飛ばされる。存在する場合はそれ以外のActivityをfinish()した上で、そのonNewInstance()を呼び出しActivityがトップにくる。
-
singleInstance(特殊): singleTaskと同様だが、Activityが属するタスクはそのActivityのインスタンスのみを唯一保持する。(singleInstanceの由来)
ユースケース
ユースケースとして、
「同じCustomViewを使った2つのActivity」を考え、それぞれをA, Bとする。CustomViewの中のあるView(ここではListとする)には、Bにintentを飛ばすというリスナーを実装する。
動作としては、
- アプリを立ち上げるとAを表示
- Aが持つListをタップするとstartActivityが呼ばれ、Bの画面が表示される。
とする。ここでA, Bともに同様のCustomViewをsetContentView()しているので、Bの画面でも表示されているListをタップするとリスナーが呼ばれて再びBのインスタンスが生成され、無限にBがスタックにpushされる現象が起きる。他にも動作が遅いアプリで連続タップなどをした場合にインスタンスが複数作られることもある。要するにActivityの多重起動となる。
そこで、
Bのlaunch Modeを<android:launchMode="singleTop">
とすると、スタックのトップにインスタンスがある場合はonCreate()
ではなくonNewIntent()
が呼ばれる。onNewIntent()
についてはこちらから。以下は引用です。
This is called for activities that set launchMode to "singleTop" in their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity(Intent). In either case, when the activity is re-launched while at the top of the activity stack instead of a new instance of the activity being started, onNewIntent() will be called on the existing instance with the Intent that was used to re-launch it.An activity will always be paused before receiving a new intent, so you can count on onResume() being called after this method.Note that getIntent() still returns the original Intent. You can use setIntent(Intent) to update it to this new Intent.
laucnhModeをセットするか、startActivity()で渡すintentにintent.setFlag(FLAG_ACTIVITY_SINGLE_TOP)
というようにタグをつけることで多重起動を防げる。2回目以降はintentを呼ばないように、、などという変な判定をしなくていいので知っておくと割と便利だと思います。
また、singleTaskとsingleInstanceは非推奨なので説明はしませんが、この2つは別タスクとしてActivityが動作するので、ほとんど使うことはないそうです。