アクティビティの埋め込みは、大画面デバイス上のアプリのタスク ウィンドウを 2 つのアクティビティ、または同じアクティビティの 2 つのインスタンスに分割することでアプリを最適化する機能です。

大画面をサポートするために従来のコードベースを更新する作業には、多大な労力と時間がかかります。フラグメントを使用してアクティビティ ベースのアプリをマルチペイン レイアウトに変換するには、大規模なリファクタリングが必要です。
アクティビティの埋め込みでは、アプリのリファクタリングはほとんど必要ありません。XML 構成ファイルを作成するか、Jetpack WindowManager API 呼び出しを行うことで、アプリがアクティビティを並べて表示するか重ねて表示するかを決定できます。
小画面のサポートは自動的に維持されます。アプリが小画面のデバイスにある場合、アクティビティは互いに重ねられます。大画面の場合、アクティビティは並べて表示されます。作成した構成に基づいてシステムで表示方法が判断されます。分岐ロジックは必要ありません。
アクティビティの埋め込みでは、デバイスの向きを変えられます。折りたたみ式デバイスでもシームレスに動作し、デバイスの折りたたみと展開に合わせて、アクティビティの積み重ねと積み重ねの解除が行われます。
最新の Android 開発では、フラグメント、ナビゲーション コンポーネント、SlidingPaneLayout
のような多用途レイアウト マネージャーを備えた、単一アクティビティ アーキテクチャが採用されています。
しかし、複数のアクティビティで構成されているアプリの場合、アクティビティの埋め込みを使用することで、タブレット、折りたたみ式デバイス、ChromeOS デバイスでのユーザー エクスペリエンスを簡単に向上させることができます。
アクティビティの埋め込みは、Android 12L(API レベル 32)以降でサポートされています。
分割タスク ウィンドウ
アクティビティの埋め込みは、アプリのタスク ウィンドウをプライマリとセカンダリという 2 つのコンテナに分割します。コンテナは、メイン アクティビティから起動されたアクティビティ、またはコンテナ内にすでに存在する他のアクティビティから起動されたアクティビティを保持します。
アクティビティは、起動時にセカンダリ コンテナ内で重ねられ、小画面ではセカンダリ コンテナがプライマリ コンテナの上に重ねられるため、アクティビティの積み重ねと「戻る」ナビゲーションは、アプリにすでに組み込まれているアクティビティの順序と一致します。
アクティビティの埋め込みを使用すると、さまざまな方法でアクティビティを表示できます。アプリは、2 つのアクティビティを同時に並べて起動することで、タスク ウィンドウを分割できます。

また、タスク ウィンドウ全体を占有するアクティビティは、新しいアクティビティを並べて起動することで、タスク ウィンドウを分割できます。

すでに分割されてタスク ウィンドウを共有しているアクティビティは、次の方法で他のアクティビティを起動できます。
横のアクティビティの上に重ねて起動:
図 4. アクティビティ A が、横のアクティビティ B の上にアクティビティ C を重ねて起動。 横に起動し、分割を横にシフトして以前のプライマリ アクティビティを非表示にする:
図 5. アクティビティ B が、横にアクティビティ C を起動して分割を横にシフト。 アクティビティをその場所の一番上(つまり同じアクティビティ スタック)に起動:
図 6. アクティビティ B が、追加のインテント フラグなしでアクティビティ C を起動。 アクティビティをそのタスクのフルウィンドウで起動:
図 7. アクティビティ A またはアクティビティ B が、タスク ウィンドウいっぱいにアクティビティ C を起動。
「戻る」ナビゲーション
アクティビティ間の依存関係やユーザーが「戻る」イベントをトリガーする方法に応じて、分割タスク ウィンドウ状態での「戻る」ナビゲーションのルールはアプリの種類によって異なる場合があります。次に例を示します。
- 一緒に: アクティビティ同士に関連性があり、一方のアクティビティを他方のアクティビティなしで表示すべきでない場合、両方を終了させるように「戻る」ナビゲーションを設定できます。
- 単独で: タスク ウィンドウ内のアクティビティ同士が完全に独立している場合、一方のアクティビティの「戻る」ナビゲーションは、他方のアクティビティの状態に影響を与えません。
ボタン ナビゲーションを使用する場合、「戻る」イベントは最後にフォーカスされたアクティビティに送信されます。ジェスチャー ベースのナビゲーションの場合、「戻る」イベントはジェスチャーが行われたアクティビティに送信されます。
マルチペイン レイアウト
Jetpack WindowManager 1.1.0 Alpha04 を使用すると、12L(API レベル 32)を搭載した大画面デバイスと、以前のバージョンのプラットフォームを搭載した一部のデバイスで、アクティビティを使ったマルチペイン レイアウトを構築できます。フラグメントやビューベースのレイアウト(SlidingPaneLayout
など)ではなく複数のアクティビティに基づく既存のアプリは、大幅なリファクタリングを必要とせずに、大画面のユーザー エクスペリエンスを向上させることができます。
一般的な例としては、リストと詳細の分割が挙げられます。質の高い表示を確保するために、システムはリスト アクティビティを起動し、その後アプリは直ちに詳細アクティビティを起動します。遷移システムは、両方のアクティビティが描画されるまで待機してから、一緒に表示します。ユーザーにとっては、2 つのアクティビティが 1 つのものとして起動します。

分割比
アプリは、分割の設定の ratio
属性によって、タスク ウィンドウの比率を指定できます(後述の分割の設定をご覧ください)。

プレースホルダ
プレースホルダ アクティビティは、アクティビティ分割の領域を占有する空のセカンダリ アクティビティです。最終的には、コンテンツを含む別のアクティビティに置き換えられます。たとえばプレースホルダ アクティビティは、リストのアイテムが選択されるまで、リストと詳細のレイアウトでアクティビティ分割のセカンダリ側を占有します。選択された時点で、プレースホルダは選択されたリストアイテムの詳細情報を含むアクティビティに置き換えられます。
プレースホルダは、分割に十分なスペースがある場合にのみ表示されます。ディスプレイ サイズがアクティビティ分割を表示できないほど小さな幅に変更されると自動的に終了しますが、スペースが許せば自動的に(再初期化した状態で)再起動します。

ウィンドウ サイズの変更
デバイス構成の変更によってタスク ウィンドウの幅が小さくなり、マルチペイン レイアウトに十分な大きさでなくなった場合(大画面の折りたたみ式デバイスがタブレット サイズからスマートフォン サイズに折りたたまれた場合や、マルチウィンドウ モードでアプリ ウィンドウがサイズ変更された場合など)、タスク ウィンドウのセカンダリ ペインにあるプレースホルダ以外のアクティビティが、プライマリ ペインのアクティビティの上に重ねられます。
プレースホルダのアクティビティは、分割するために十分な表示幅がある場合にのみ表示されます。小画面では、プレースホルダは自動的に閉じられます。表示領域が再び十分な大きさになると、プレースホルダが再作成されます(前述のプレースホルダをご覧ください)。
アクティビティを重ねることができるのは、WindowManager
がセカンダリ ペインのアクティビティをプライマリ ペインのアクティビティの上に Z オーダーで表示するためです。
セカンダリ ペインの複数のアクティビティ
アクティビティ B が追加のインテント フラグなしで、アクティビティ C を所定の位置で起動します。
その結果、同じタスクのアクティビティの Z オーダーは次のようになります。
タスク ウィンドウが小さくなるとアプリは 1 つのアクティビティに縮小され、アクティビティ C がスタックの一番上に重ねられます。
小さいウィンドウで「戻る」操作を行うと、重ねられた各アクティビティ間で移動します。
タスク ウィンドウ構成を、複数のペインに対応できる大きなサイズに復元すると、アクティビティは再び並んで表示されます。
分割の積み重ね
アクティビティ B が、横にアクティビティ C を起動して分割を横にシフトします。
その結果、同じタスクのアクティビティの Z オーダーは次のようになります。
アプリは、タスク ウィンドウが小さくなると、アクティビティ C が一番上にある 1 つのアクティビティに縮小されます。
分割の設定
コンテナと分割は、分割ルールに基づいて WindowManager ライブラリで作成できます。分割ルールの設定手順は以下のとおりです。
最新の WindowManager ライブラリ依存関係を
build.gradle
ファイルに追加します。次に例を示します。implementation 'androidx.window:window:1.1.0-alpha04'
次の処理を行うリソース ファイルを作成します。
- 分割を共有するすべてのアクティビティの分割オプションを設定する
- フィルタを使用して分割するアクティビティを定義する
- 分割に配置しないアクティビティを指定する
例:
<!-- main_split_config.xml --> <!-- The split configuration for activities. --> <resources xmlns:window="http://schemas.android.com/apk/res-auto"> <!-- Define a split for the named activity pair. --> <SplitPairRule window:splitRatio="0.3" window:splitMinWidth="600dp" window:finishPrimaryWithSecondary="never" window:finishSecondaryWithPrimary="always"> <SplitPairFilter window:primaryActivityName=".SplitActivityList" window:secondaryActivityName=".SplitActivityDetail"/> </SplitPairRule> <!-- Automatically launch a placeholder for the list activity. --> <SplitPlaceholderRule window:placeholderActivityName=".SplitActivityListPlaceholder" window:splitRatio="0.3" window:splitMinWidth="600dp"> <ActivityFilter window:activityName=".SplitActivityList"/> </SplitPlaceholderRule> <!-- Define activities that should never enter a split. Note: Takes precedence over other split rules. --> <ActivityRule window:alwaysExpand="true"> <ActivityFilter window:activityName=".FullscreenActivity"/> </ActivityRule> </resources>
ルールの定義をライブラリに伝えます。
この例では、アプリの他のコンポーネントが読み込まれてアクティビティが起動する前に、Jetpack Startup ライブラリを使用して初期化を行います。この Startup の機能を有効にするには、アプリのビルドファイルにライブラリ依存関係を追加します。
implementation 'androidx.startup:startup-runtime:1.1.1'
アプリ マニフェストに次のエントリを追加します。
<!-- AndroidManifest.xml --> <provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <!-- This entry makes ExampleWindowInitializer discoverable. --> <meta-data android:name="androidx.window.sample.embedding.ExampleWindowInitializer" android:value="androidx.startup" /> </provider>
最後に、Initializer クラスの実装を追加します。
ルールを設定するには、
SplitController.initialize()
に定義(main_split_config
)を含む XML リソース ファイルの ID を指定します。Kotlin
class ExampleWindowInitializer : Initializer<SplitController> { override fun create(context: Context): SplitController { SplitController.initialize(context, R.xml.main_split_config) return SplitController.getInstance(context) } override fun dependencies(): List<Class<out Initializer<*>>> { return emptyList() } }
Java
class ExampleWindowInitializer extends Initializer<SplitController> { @Override SplitController create(Context context) { SplitController.initialize(context, R.xml.main_split_config); return SplitController.getInstance(context); } @Override List<Class<? extends Initializer<?>>> dependencies() { return emptyList(); } }
分割の例
フルウィンドウからの分割

リファクタリングは必要ありません。分割の設定を静的に、またはランタイムに定義し、追加のパラメータなしで Context#startActivity()
を呼び出すことができます。
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
デフォルトでの分割
アプリのランディング ページが、大画面で 2 つのコンテナに分割されるように設計されている場合、両方のアクティビティを同時に作成して表示すると最良のユーザー エクスペリエンスが得られます。ただし、ユーザーがプライマリ コンテナでアクティビティを操作する(ナビゲーション メニューからアイテムを選択するなど)まで、分割のセカンダリ コンテナでコンテンツを利用できない場合があります。プレースホルダ アクティビティは、分割のセカンダリ コンテナにコンテンツを表示できるようになるまで、空白を埋めることができます(前述のプレースホルダをご覧ください)。

プレースホルダを伴う分割を作成するには、プレースホルダを作成し、プライマリ アクティビティに関連付けます。
<SplitPlaceholderRule
window:placeholderIntentName=".Placeholder">
<ActivityFilter
window:activityName=".Main"/>
</SplitPlaceholderRule>
ディープリンク分割
アプリがインテントを受け取ると、ターゲット アクティビティをアクティビティ分割のセカンダリ部分として表示できます(リストのアイテムに関する情報を詳細画面に表示するリクエストなど)。詳細は、小さいディスプレイではタスク ウィンドウ全体に表示され、大きいデバイスではリストの横に表示されます。

起動リクエストはメイン アクティビティにルーティングされ、ターゲットの詳細アクティビティは分割で起動する必要があります。SplitController
は、利用可能な表示幅に基づいて、適切な表示方法(積み重ねまたは横並び)を自動的に選択します。
Kotlin
override fun onCreate(savedInstanceState Bundle?) { … splitController.registerRule(SplitPairRule(newFilters)) startActivity(Intent(this, DetailActivity::class.java)) }
Java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { … splitController.registerRule(new SplitPairRule(newFilters)); startActivity(new Intent(this, DetailActivity.class)); }
「戻る」ナビゲーション スタックでユーザーが利用できるアクティビティが、ディープリンクのデスティネーションのみの場合があります。その場合も含めて、詳細アクティビティが閉じてメイン アクティビティだけが残る、ということがないようにしてください。
代わりに、finishPrimaryWithSecondary
属性を使用することで両方のアクティビティを同時に終了できます。
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".List"
window:secondaryActivityName=".Detail"/>
</SplitPairRule>
分割コンテナ内の複数のアクティビティ
分割コンテナに複数のアクティビティを重ねると、ユーザーは深いコンテンツにアクセスできます。たとえばリストと詳細の分割で、ユーザーがサブ詳細セクションに移動する必要がある場合でも、プライマリ アクティビティはそのまま表示し続けます。

Kotlin
class DetailActivity { … fun onOpenSubDetail() { startActivity(Intent(this, SubDetailActivity::class.java)) } }
Java
public class DetailActivity { … void onOpenSubDetail() { startActivity(new Intent(this, SubDetailActivity.class)); } }
サブ詳細アクティビティが、詳細アクティビティを隠すように、上に配置されます。
すると、ユーザーはスタック内をさかのぼって移動することで前の詳細レベルに戻ることができます。

同じセカンダリ コンテナ内のアクティビティからアクティビティを起動すると、アクティビティは互いに重ねられます。これがデフォルトの動作です。アクティブな分割の中でプライマリ コンテナから起動されたアクティビティも、アクティビティ スタックの一番上にあるセカンダリ コンテナに配置されます。
新しいタスクのアクティビティ
分割タスク ウィンドウ内のアクティビティが新しいタスクのアクティビティを起動すると、新しいタスクは、分割を含むタスクとは別に、ウィンドウ全体に表示されます。履歴画面には 2 つのタスク(分割の中のタスクと新しいタスク)が表示されます。

アクティビティの置き換え
セカンダリ コンテナ スタック内でアクティビティを置き換えることができます(プライマリ アクティビティをトップレベル ナビゲーションに使用し、セカンダリ アクティビティが選択したデスティネーションである場合など)。トップレベル ナビゲーションから選択されるたびに、セカンダリ コンテナで新しいアクティビティが起動し、それまでそこにあったアクティビティは削除されます。

ナビゲーションの選択が変更されたときにアプリがセカンダリ コンテナのアクティビティを終了しない場合、分割が閉じられた(デバイスが折りたたまれた)ときに「戻る」ナビゲーションがわかりにくくなる可能性があります。たとえば、プライマリ ペインにメニューがあり、セカンダリ ペインに画面 A と B が重ねられている場合、ユーザーがスマートフォンを折りたたむと、B が A の上になり、A がメニューの上になります。ユーザーが B から戻ると、メニューではなく A が表示されます。
このような場合は、画面 A をバックスタックから削除する必要があります。
既存の分割の上に新しいコンテナで横に起動する場合のデフォルト動作では、新しいセカンダリ コンテナが上に配置され、古いコンテナがバックスタックに保持されます。clearTop
で以前のセカンダリ コンテナを消去して新しいアクティビティを通常どおり起動するように、分割を設定できます。
<SplitPairRule
window:clearTop="true">
<SplitPairFilter
window:primaryActivityName=".Menu"
window:secondaryActivityName=".ScreenA"/>
<SplitPairFilter
window:primaryActivityName=".Menu"
window:secondaryActivityName=".ScreenB"/>
</SplitPairRule>
Kotlin
class MenuActivity { … fun onMenuItemSelected(selectedMenuItem: Int) { startActivity(Intent(this, classForItem(selectedMenuItem))) } }
Java
public class MenuActivity { … void onMenuItemSelected(int selectedMenuItem) { startActivity(new Intent(this, classForItem(selectedMenuItem))); } }
あるいは、同じセカンダリ アクティビティを使用し、プライマリ(メニュー)アクティビティから、同じインスタンスに解決されてセカンダリ コンテナで状態または UI の更新をトリガーする新しいインテントを送信します。
複数の分割
アプリは、追加のアクティビティを横に起動することで、多層の深いナビゲーションを提供できます。
セカンダリ コンテナのアクティビティが新しいアクティビティを横に起動すると、既存の分割の上に新しい分割が作成されます。

バックスタックには以前開かれたアクティビティがすべて含まれているため、ユーザーは C を終了した後に A / B 分割に移動できます。
新しい分割を作成するには、既存のセカンダリ コンテナから新しいアクティビティを横に起動します。A / B 分割と B / C 分割の両方の設定を宣言し、アクティビティ C を通常どおり B から起動します。
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
<SplitPairFilter
window:primaryActivityName=".B"
window:secondaryActivityName=".C"/>
</SplitPairRule>
Kotlin
class B { fun onOpenC() { startActivity(Intent(this, C::class.java)) } }
Java
public class B { … void onOpenC() { startActivity(new Intent(this, C.class)); } }
分割状態の変更に対応する
アプリ内の異なるアクティビティに、同じ機能を果たす UI 要素が存在することがあります(アカウント設定を含むウィンドウを開くコントロールなど)。

分割の中に共通の UI 要素を持つ 2 つのアクティビティがある場合、その要素を両方のアクティビティに表示することは冗長であり、混乱を招くおそれがあります。

アクティビティが分割の中にあることを確認するには、分割状態の変更について SplitController
でリスナーを登録します。次に、それに応じて UI を調整します。
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { splitController .addSplitListener(this, mainThreadExecutor, SplitInfoChangeCallback()) } inner class SplitInfoChangeCallback : Consumer<List<SplitInfo>> { override fun accept(splitInfoList: List<SplitInfo>) { findViewById<View>(R.id.infoButton).visibility = if (!splitInfoList.isEmpty()) View.GONE else View.VISIBLE } }
Java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { splitController .addSplitListener(this, mainThreadExecutor, SplitInfoChangeCallback()); } class SplitInfoChangeCallback extends Consumer<List<SplitInfo>> { public void accept(List<SplitInfo> splitInfoList) { findViewById<View>(R.id.infoButton).visibility = !splitInfoList.isEmpty()) ? View.GONE : View.VISIBLE; } }
コールバックは、アクティビティが停止している場合を含め、どのようなライフサイクル状態でも発生する可能性があります。リスナーは通常、onStart()
で登録し、onStop()
で登録を解除します。
フルウィンドウ モーダル
ログイン画面、ポリシーの確認画面、エラー メッセージなど、アクティビティの中には、指定されたアクションが行われるまでユーザーがアプリを操作できないようにするものもあります。モーダル アクティビティは、分割に表示されないようにする必要があります。
Expand 設定を使用することで、アクティビティが常にタスク ウィンドウ全体に表示されるよう強制できます。
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".FullWidthActivity"/>
</ActivityRule>
アクティビティを終了する
ディスプレイの端からスワイプすることで、分割のどちらかの側のアクティビティを終了できます。


デバイスがジェスチャー ナビゲーションではなく [戻る] ボタンを使用するように設定されている場合、入力はフォーカスされているアクティビティ(最後にタップまたは起動されたアクティビティ)に送信されます。
分割のアクティビティを 1 つ終了した場合の結果は、分割の設定によって異なります。
デフォルト設定
分割のアクティビティを 1 つ終了すると、残りのアクティビティがウィンドウ全体を占有します。
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
アクティビティをまとめて終了する
セカンダリ アクティビティが終了すると、プライマリ アクティビティが自動的に終了します。
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
プライマリ アクティビティが終了すると、セカンダリ アクティビティが自動的に終了します。
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
プライマリまたはセカンダリが終了したときに、アクティビティをまとめて終了します。
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
コンテナの複数のアクティビティを終了する
分割コンテナで複数のアクティビティが重なっている場合、その一番下にあるアクティビティが終了しても、上にあるアクティビティが自動的に終了することはありません。
たとえば、2 つのアクティビティがセカンダリ コンテナにあり、B の上に C があるとします。
分割の設定はアクティビティ A とアクティビティ B の設定によって定義されます。
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
一番上のアクティビティを終了しても分割は保持されます。
セカンダリ コンテナの一番下(ルート)にあるアクティビティを終了しても、その上にあるアクティビティは削除されません。そのため、分割も保持されます。
プライマリ アクティビティとともにセカンダリ アクティビティを終了するなど、アクティビティをまとめて終了するための追加のルールも実施されます。
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
分割がプライマリとセカンダリをまとめて終了するように設定されている場合は次のようになります。
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
ランタイムに分割プロパティを変更する
現在アクティブな、表示されている分割のプロパティは変更できません。分割ルールの変更は、追加のアクティビティ起動と新しいコンテナに影響しますが、既存のアクティブな分割には影響しません。
アクティブな分割のプロパティを変更するには、横のアクティビティまたは分割の中のアクティビティを終了し、新しい設定でアクティビティを再び横に起動します。
分割からアクティビティを抽出してフルウィンドウにする
横のアクティビティをフルウィンドウ表示する新しい設定を作成してから、同じインスタンスに解決されるインテントでそのアクティビティを再起動します。
ランタイムに分割のサポートを確認する
アクティビティの埋め込みは Android 12L(API レベル 32)の機能ですが、デバイスによっては、それより前のプラットフォーム バージョンでも利用できます。この機能が利用可能かどうかをランタイムに確認するには、SplitController.isSplitSupported()
メソッドを使用します。
Kotlin
val splitController = SplitController.Companion.getInstance() if (splitController.isSplitSupported()) { // Device supports split activity features. }
Java
SplitController splitController = SplitController.Companion.getInstance(); if (splitController.isSplitSupported()) { // Device supports split activity features. }
分割がサポートされていない場合、(アクティビティの埋め込み以外のモデルに従って)アクティビティは一番上に起動されます。
システムのオーバーライドを禁止する
Android デバイスのメーカー(相手先ブランド製品製造企業、OEM)は、デバイス システムの機能としてアクティビティの埋め込みを実装できます。システムは、アプリのウィンドウ処理動作をオーバーライドして、マルチアクティビティ アプリの分割ルールを指定します。システムによるオーバーライドが行われると、マルチアクティビティ アプリはシステム定義のアクティビティ埋め込みモードになります。
システムのアクティビティの埋め込みにより、アプリに変更を加えることなく、リスト詳細などのマルチペイン レイアウトを使用してアプリの表示を改善できます。ただし、誤ったレイアウトでアプリが表示されたり、バグや、アプリ側で実装するアクティビティ埋め込みとの競合を引き起こしたりすることもあります。
システムのアクティビティの埋め込みを禁止または許可するには、アプリ マニフェスト ファイルでプロパティを設定します。次に例を示します。
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<property
android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE"
android:value="true|false" />
</application>
</manifest>
プロパティ名は Jetpack WindowManager WindowProperties オブジェクトで定義されます。アクティビティの埋め込みをアプリが実装する場合、またはシステムがアクティビティの埋め込みのルールをアプリに適用しないようにする場合は、値を false
に設定します。値を true
に設定すると、システムはシステム定義のアクティビティの埋め込みをアプリに適用できるようになります。
制約、制限、注意事項
- タスク内の他のアクティビティを整理したり、埋め込んだりできるのは、タスクのホストアプリ(タスクのルート アクティビティのオーナーとして識別)に限られます。埋め込みと分割をサポートするアクティビティが、別のアプリに属するタスクで実行される場合、それらのアクティビティでは埋め込みと分割が機能しません。
- アクティビティは 1 つのタスク内でのみ整理できます。新しいタスクでアクティビティを起動すると、常に既存の分割の外部で新しく開いたウィンドウに配置されます。
- 整理して分割に配置できるのは、同じプロセスのアクティビティに限られます。異なるプロセスのアクティビティを把握する方法がないため、
SplitInfo
コールバックは同じプロセスに属するアクティビティのみをレポートします。 - 各ペアまたは単一のアクティビティ ルールは、ルールが登録された後に発生するアクティビティ起動にしか適用されません。現在のところ、既存の分割やその視覚的なプロパティを更新する方法はありません。
- 分割ペアのフィルタ設定は、アクティビティを起動するときに使用するインテントと完全に一致する必要があります。この照合はアプリプロセスから新しいアクティビティが起動された時点で起こるため、暗黙的インテントを使用する場合、システム プロセスの後半で解決されるコンポーネント名が不明となることがあります。起動時にコンポーネント名が不明な場合は、代わりにワイルドカード(「*/*」)を使用し、インテントのアクションに基づいてフィルタリングを実施できます。
- 現在のところ、コンテナ間でアクティビティを移動する方法や、分割の作成後にその内外にアクティビティを移動する方法はありません。分割は、ルールが一致する新しいアクティビティが起動したときにのみ、WindowManager ライブラリによって作成され、分割コンテナ内の最後のアクティビティが終了したときに破棄されます。
- アクティビティは構成変更に伴って再起動される場合があるため、分割が作成または削除されてアクティビティの境界が変化すると、それまでのインスタンスが完全に破棄され新たなインスタンスが再作成される可能性があります。そのため、アプリ デベロッパーは、ライフサイクル コールバックから新しいアクティビティを起動するなどの処理に注意する必要があります。