minimize

事業拡大のため、新しい仲間を募集しています。
→詳しくはこちら

アプリケーションを起動すると、メインの Activity が起動します。
この Activity は Task と呼ばれる場所(スタック)に格納されます。
※ Activity は UI を持ったコンポーネント

次にこの Activity が別の Activity を呼び出すと、その Activity は
同じスタック上に積まれます(PUSH)。

App-A  Activity-A
App-B  Activity-B1
App-B  Activity-B2
App-C  Activity-C

このように、スタックは異なるアプリケーションの Activity をまとめて持つことができます。
これによって、アプリケーションを使うユーザはそれらが別々のアプリケーションであることを
意識せずに作業することができます。

上の状態で Activity-C が完了する、もしくは [戻る] キーを押すと、最上位の Activity がスタックから POP されます。
つまり、以下のようになります。

App-A  Activity-A
App-B  Activity-B1
App-B  Activity-B2

ここから Activity-A を表示させたかったら、Activity-B2, B1 の順でスタックから POP することになります。

App-A  Activity-A
App-B  Activity-B1
App-B  Activity-B1

↑こんな事もあり得ます。この場合、Activity-B1 はそれぞれ異なるインスタンスとなります。
つまり、両者は互いに独立したオブジェクトを保持します。

Task は常に Activity のスタックであり、他の要素が入ることはありません。

最上位の Activity

現在表示されている(=最後にPUSHされた) Activity を指します。

Root Activity

最初に Task に積まれた Activity を指します。
通常これはアプリケーションの Main Activity ですが、そうでない場合もあり得ます(後述)。

Task の切り替え

今まで説明してきたとおり、Task とは Activity の束(スタック)です。
Task 内に積まれた全ての Activity は、一つの単位(Unit)として一緒に移動します。

例えば、4つの Activity が積まれた Task-A がある場面を考えます。
ここでユーザが [HOME] キーを押して、別のアプリケーションを実行したとします。

このとき、新しく Task-B が生成されます。
そして Task-A の4つの Activity は、丸ごとバックグラウンドに移動します。

ユーザが Task-B を実行中に、再度 [HOME] を押して、今度は最初に実行していたアプリケーションを
選択したとします。このとき、Task-B は丸ごとバックグラウンドに移動し、Task-A が丸ごとフォアグラウンドに移動します。
ここでユーザが [戻る] を押すと、Task-A のスタックから一つ Activity が POP されます。
※ Task-B に移ることは無い
もし Task-B に移りたかったら、ユーザは [HOME] から対象のアプリケーションを選択する必要があります。

これらの挙動はあくまでデフォルト動作であり、ほとんどが変更可能です。

Affinity

和訳すると「親和性」なのですが、わかりにくいので英語のままでいきます。

Affinity が同じ Activity 同士は、同じ Task 内に積まれます。
一方、Affinity が異なる(=親和性の無い)Activity 同士は別の Task 上に積まれます。
言い換えれば、Task は同一の Affinity を有した Activity を束にして持つスタックということになります。

コンポーネントのデフォルト Affinity の値は、アプリケーション(のID)と同じになります。
つまり同一アプリケーションのコンポーネントは同一の Task に積まれ、
別のアプリケーションのコンポーネントは別の Task に積まれます。

Affinity の制御をする要素を、以下に挙げます。

FLAG_ACTIVITY_NEW_TASK

通常は、ある Activity を起動すると、それは呼び出し側の Activity と同じ Affinity を持ちます。
※ この Affinity はデフォルト値と異なる可能性があります(別アプリケーションから起動された場合)

しかし、startActivity() に渡した Intent に FLAG_ACTIVITY_NEW_TASK フラグが含まれている場合
Android システムはその Activity を別のタスクに収容しようとします。
これによって、呼び出し側が強制的に呼び出し先の Activity を別の Task に入れることができます。

allowTaskReparenting

ちょっとややこしいので具体例を。
二つのアプリケーションがあったとします。

App-A
  Activity-A1 (Affinity = A)
  Activity-A2 (Affinity = A)
App-B
  Activity-B1 (Affinity = B)

それぞれを単独で起動させると、上のような Affinity になるでしょう。

ここで、B1 から A1 を起動(startActivity)したとしましょう。
この場合、A1 の Affinity は呼び出し側と同じ Affinity を持つので
以下のようになります。

Activity-B1 (Affinity = B)
Activity-A1 (Affinity = B)

その後、App-A がフォアグラウンドに戻ったとします。
A1 の allowTaskReparenting = "false" だと、Affinity は以下のようになります。

App-A
  Activity-A1 (Affinity = B)
  Activity-A2 (Affinity = A)

このように、A1 と A2 の Affinity が違っています。この場合、両者は別々のタスクで動くことになります。
一方、A1 の allowTaskReparenting = "true" だと、Affinity は以下のようになります。

App-A
  Activity-A1 (Affinity = A)
  Activity-A2 (Affinity = A)

A1 の Affinity が、B → A に変わったのがわかるでしょうか。
これが、allowTaskReparenting = true の意味です。つまり、そのコンポーネントの親アプリケーションが
フォアグラウンドになった時、このコンポーネントの Affinity がデフォルトの値(アプリケーションID)に戻るということです。

Stack のクリア

ユーザが Task を長時間放置すると、システムは Task の Root Activity を除く
全ての Activity をクリアします。
この状態でユーザが Task に戻ると、最初の画面(最後ではなく!)が表示されることになります。

以下の属性によって、このデフォルト動作をカスタマイズすることができます。

alwaysRetainTaskState

タスクの Root Activity (つまり Main Activity)でこの属性を true にすると
Stack のクリアは一切行われなくなります。

clearTaskOnLaunch

タスクの Root Activity でこの属性を true にすると、
ユーザは一瞬でもその Task を離れたとき「Rootも含めた」全ての Activity がクリアされます。

finishOnTaskLaunch

この属性のみ、Root Activity 以外の Activity にも適用することが可能です。
この属性を true にすると、ユーザは一瞬でもその Task を離れたとき
自身の Activity だけがクリアされます。

Task の開始について

ある Activity を Task のエントリポイントとして設定するには、以下の Intent Filter を Activity 内部で定義します。

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

最初に Android アプリケーションを作成するときに作られた Activity には
上記の設定が既に入っています。
ですから、アプリケーションを起動したときにその Activity が表示されるのです。

この Filter を追加した Activity は、Android のアプリケーションランチャに表示されるようになります。
ここに表示しておかないと、この Activity(を含む Task)を一旦バックグラウンドにしてしまうと
その後この Task に戻るための手段が無くなってしまいます。
前述した FLAG_ACTIVITY_NEW_TASK フラグにも、これと同じ事が起こる危険性があります。