Androidのactivityとtask

前置き

私が新しいプラットフォーム上でプログラミングするとき、まず知りたいと思うのは、それがどんなスレッドモデルを採用しているのか、です。言い換えると、OSのスケジューリング対象は何かということです。Windowsならスレッドだし、μITRONならタスクということになります。

JavaベースのAndroidの場合は、java.lang.Threadがスケジューリング対象のはずですが、リファレンスマニュアルなどを読んでいるとtaskという単語に出会うこともあります。そこで、Androidのtaskについて整理します。

※この記事で言うtaskは、android.os.AsyncTaskとは別の意味のtaskです。

本文

taskとは

結論から言えば、Andoridで言うtaskはactivityをグループ化したものです(OSスケジューリングとは全く関係ありません)。DevGuideでは、「ユーザの視点から見たアプリケーション」といった書き方をされています。例えば、受信したメールを表示する画面から、メール内のURLリンクをタッチしてブラウザの画面へ遷移したとき、(プログラム上はapplicationが切り替わっているけど)ユーザから見ると同じアプリ内で画面遷移したように感じるでしょ、というのがGoogleの言い分のようです。

どのようにグループ化するかは、(起動する、あるいは起動される)applicationが決めます。なので、ユーザから見ると同じアプリ内の画面遷移でも、実は裏ではtaskが切り替わっているかもしれません。

activityスタック

taskは、activityをスタック状に管理します。task内のactivityが別のactivityをstartさせると、新しいactivityがスタックの一番上に乗ります。例えばユーザがBACKキーを押して新しいactivityを終了させると、上から2番目のactivityが再開します。

task1の中で、activity2がactivity3をstartさせ、activity3の中でBACKキーが押された場合の様子を下図に示します。スタックのBOTTOMにいるactivityはroot activtyと呼ばれ、TOPにいるactivityはrunning activityと呼ばれます。

activityスタック

task生成

taskという概念を使ったactivityのグループ化に関して、ユーザが手出しできることが一つだけあります。それは、Launcherからアプリを(厳密にはactivityを)起動することです。普通、HOMEキーを押すと、どんな画面からでもホーム画面(Launcher)へ戻れますが、そこから何かactivityをstartさせると、原則として新しいtaskが生成され、そのactivityがroot activityとなります。

例を挙げて説明します。下図のように、3つのApplicationクラスがあり、それぞれがActivityクラスを持っているとしましょう。

apps

LauncherからApp1のAct1を開始(①)すると、それをrootとするtask1が生成されます。そこからintentを使ってApp2のAct2を開始(②)し、さらにApp2のAct1を開始(③)しても、新しいtaskは生成されずtask1上に積まれていきます。ここでHOMEキーを押してLauncherに戻り、App3のAct1を開始(④)すると、それをrootとするtask2が生成されます。app3-act1がintentを使ってApp2のAct2を開始(⑤)すると、それはtask2上に積まれます。

story

このように、同じtask内に、異なるapplicationのactivityが同居することが可能です。また、同じActivityクラスのインスタンスが複数個存在することも可能です。

applicationによる制御

これまで説明したのは、あくまでもデフォルトの挙動です。applicationは、色々な方法でこの挙動を変えることができます。場合によっては、スタックらしからぬ動き(中間のactivityだけが終了するとか)も起き得ます。

launchMode

マニフェストに記述する<application>要素や<activity>要素には、activity生成時のtask制御に関する属性がいくつかあります。中でも重要なのは<activity>要素のlaunchMode属性でしょう。これによりactivityの性格が決まると思います。設定可能な値は、standard、singleTop、singleTask、singleInstanceの4種類で、standardがデフォルトです。それぞれの違いを下表に示します。

launchMode

affinity、NEW_TASKフラグ、allowTaskReparenting

affinityとは「親近感」みたいな意味です。同じaffinityを持つactivity同士は、同じtask内に収まりやすいという性質があります。taskのaffinityは、root activityのaffinityで決まります。activityのaffinityは、<activity>要素のtaskAffinity属性で決まります。これが指定されてない場合、<application>要素のtaskAffinityが使われます。それも指定されてない場合は、<manifest>要素のpackage属性値がaffinityとして使われます。

affinityが作用するのは、FLAG_ACTIVITY_NEW_TASK付きのintentを使ってactivityをstartさせたときです。このフラグは、本来、新規taskの生成を促すものですが、もし当該activityと同じaffinityのtaskがあるなら(つまり同じaffinityのactivityをrootに持つtaskがあるなら)、そのtask上に当該activityを生成します。

また<application>要素と<activity>要素のallowTaskReparenting属性にもaffinityが作用します。通常、activityが一旦作成されると、別のtaskへ移動することはありません。しかし、allowTaskReparentingがtrueに設定されたactivityは、同じaffinityを持つtaskがFG(foreground)に来たとき、そのtaskへ移動します。このとき、移動するactivityは移動元taskのTOPにいなくても構いません(スタックの中間のactivityでも移動する)。

alwaysRetainTaskState

通常、長時間BG(background)にいるtask上のroot activity以外のactivityは、強制的に終了されます。しかし、<activity>要素のalwaysRetainTaskState属性をtrueに設定しておけば強制終了を抑止できます。

CLEAR_TOPフラグ

FLAG_ACTIVITY_CLEAR_TOP付きのintentを使ってactivityをstartさせると、当該activityが既にカレントtask上に存在する場合、そのactivityより上のactivityを全て強制終了してから、そのactivityをre-useします。さらに当該activityのlaunchModeがstandardなら、そのactivity自体も強制終了して新しく当該activityのインスタンスを生成します。

clearTaskOnLaunch、finishOnTaskLaunch

taskが、<activity>要素のclearTaskOnLaunch属性がtrueにセットされたactivityをrootに持つ場合、そのtaskがBGに行くとき(あるいはBGからFGに来るとき)、root以外の全てのactivityが強制終了されます。

<activity>要素のfinishOnTaskLaunch属性がtrueにセットされたactivityは、自taskがBGに行くとき(あるいはBGからFGに来るとき)、強制終了されます。そのactivityがtaskのTOPにいなくても関係ありません(スタックの中間のactivityでも終了する)。

Last modified:2011/02/28 12:18:25
Keyword(s):
References:[くろニャァ ~ Activityとリソース] [Androidアプリ開発]
This page is frozen.