12月20日。 2018 – 6 min read
API 11以前は、新しいページを画面にすべて表示する活動を行なっていました。 現在では、API 28 のフラグメントとナビゲーション ツールを使用すると、1 つのアクティビティで非常に複雑なアプリを作成することが可能です。 しかし、アクティビティは、アプリをステージやプロセスに区分けするのには、今でも最適です。 たとえば、すべてのマーケティングを1つのアクティビティに分割し、実際のアプリを独自のアクティビティにすることができます。 また、チャットサービスのような機能用に1つのセクションを確保することもできます。 アクティビティの起動モードを知ることで、ユーザーにとって意味のある方法で、これらのプロセスをより適切に分割することができます。 そこで今回は、アクティビティ起動モードをブログで紹介し、GIFアニメーションを用いてコンセプトを説明し、皆さんと共有したいと思います。 お楽しみください!
起動モードについて話す前に、まずタスクの役割について理解しましょう。 タスクは、バックスタックと呼ばれるスタックに配置されたアクティビティのコレクションを保持します。 タスクで最初に起動されるアクティビティは、ルート アクティビティです。 ルート アクティビティで戻るボタンを押すと、アクティビティが停止するだけでなく、タスクや、場合によってはアプリも停止します。
では、いくつかの起動モードについて説明します。 ここで、先ほど作成した B から別のアクティビティ B を起動したとすると、アクティビティ B のインスタンスが 2 つスタックされることになります。 ユーザーが戻るボタンを押すと、別のアクティビティBのインスタンスに戻ることになります。 これは、ユーザーにとって非常に混乱することでしょう。 何があってもアクティビティを重ねて作成することを、「標準起動モード」と呼びます。 マニフェストのアクティビティ XML で起動モードが定義されていない場合、アクティビティは標準起動モードを使用します。
さて、標準モードがユーザーにとっていかに厄介であるかが分かったので、次に単一トップ起動モードを理解してください。 この起動モードでは、同じアクティビティの異なるインスタンスが互いに積み重ねられることを防ぎます。 例えば、アクティビティBがシングルトップであるとします。 マニフェストで次のように起動モードを定義できます。
///AndroidManifest.xml <application ...> <activity android:name=".Activity_A"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Activity_B" android:launchMode="singleTop"/> <activity android:name=".Activity_C"/> <activity android:name=".Activity_D"/> </application>
つまり、アクティビティ B からアクティビティ B を起動すると、B の新しいインスタンスを作成して古い B の上に重ねるのではなく、インテントが B の現在のインスタンスに渡されるのです。 シングル トップ起動モードの主なコンセプトは、同じアクティビティの 2 つのインスタンスを互いに積み重ねることはできないということです。
シングル トップ起動モードを使用中に、タスクに同じシングル トップ アクティビティの 2 つのインスタンスが必要ない場合、インテントで FLAG_ACTIVITY_CLEAR_TOP 定数を渡すことができます。 例として、アクティビティスタックがABC(Bはシングルトップ)であるとし ます。 FLAG_ACTIVITY_CLEAR_TOP を使用して C から B を起動すると、スタックは B までポップダウンし、インテントが B のまさにそのインスタンスに渡されます。
// code example for passing the constant flag in your intentIntent intent = new Intent(this, Activity_B.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent);
次に、シングルタスクという起動モードがあります。 この起動モードでは、アプリ内のすべてのタスクを通して、アクティビティは1つのタスクにのみ属することができると述べています。 したがって、FLAG_ACTIVITY_CLEAR_TOP 動作と同様に、スタックが ABC で、C から B (単一タスク) を起動した場合、B までポップダウンし、そのインスタンスにインテントを渡します。 ここで、タスクアフィニティが登場します。 タスク アフィニティでは、アクティビティをどのタスクに所属させるかを定義できます。 デフォルトでは、アクティビティはそのルート アクティビティと同じタスク親和性を持ちます。 タスク アフィニティを使用すると、アクティビティを異なるタスクに分離できます。
<activity android:name=".Activity_A" android:taskAffinity="com.affinity.of.a"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity><activity android:name=".Activity_B" android:launchMode="singleTask" android:taskAffinity="com.affinity.of.b" />
ここで、アクティビティ A とアクティビティ B は異なるタスク アフィニティを持ちます。 A がタスク 1 で作成されると、C が A から起動されます。デフォルトでは、各アクティビティはそのルートと同じアフィニティを持っているので、まだタスク 1 にいます。 Bは異なるタスク親和性を持つので、タスク2のルートになり、タスク2がフォアグラウンドに移動します。 BからアクティビティCの新しいインスタンスを起動すると、ルートアクティビティ(この場合、B)のタスク親和性であるため、Cはタスク2に属します。 しかし、ここでタスク2のCからAを起動しようとするとどうなるでしょうか。 Aの親和性はタスク1なので、タスク2からタスク1にシフトし、アクティビティAにポップバックし、最後にAにインテントを渡します。
Single Taskを知っていれば、最後の起動モード、シングルインスタンスをより理解することができます。 シングルタスクと同様に、シングルインスタンスを持つアクティビティは、すべてのタスクで唯一のアクティビティになることができます。 この例では、アクティビティ B の起動モードは Single Instance です。 タスク1のアクティビティAからアクティビティBが起動されます。 これにより、アクティビティBは新しいタスクで起動され、フォアグラウンドに置かれます。 Single Instanceはタスク内の唯一のアクティビティであるため、Cはタスク1のアクティビティAの上に起動され、タスク1がフォアグラウンドになります。
Task affinityもSingle Instanceで役割を果たします。 アクティビティ B にタスクの親和性がない場合、ユーザーはタスク 1 に戻ってナビゲートすることはできません。 B にタスクの親和性がある場合、ユーザーはタスク 1 とタスク 2 の間を行き来できます。
起動モードについて知っていると、ユーザーにとって良い UI/UX 体験になり、頭を悩ませるバグも解消できるため、この情報もお役に立てることを願っています。
この概念をよりよく理解するために、Anil Deshpande の CodeTutor youtube ページに賛辞を送りたいと思います。 このテーマに関する 7 つの動画のうち、最初の動画はこちらです。 https://www.youtube.com/watch?v=m8sf0UkJkxo