Activity嵌入适配指导更新时间: 2025-04-21 09:41:00

一、背景

Android从12L开始支持通过Jetpack Window实现activity嵌入功能,对于大屏体验有很大的提高。vivo从12L(包括T版本)、OPPO和小米从T版本开始,都支持Jetpack Window实现activity嵌入,希望开发者尽快适配android activity嵌入方案,提高应用在大屏设备的用户体验。在阅读适配文档时,建议开发者结合android WindowManager demo一起理解,便于尽快熟悉activity嵌入新功能。

Jetpack WindowManager demo

 https://github.com/android/user-interface-samples/tree/main/WindowManager

Android activity嵌入适配指导

 https://developer.android.com/guide/topics/large-screens/activity-embedding

二、 activity嵌入适配

2.1 优势和用途

优势:

  • activity 嵌入只需要对应用进行很少的重构或根本不需要对应用进行重构。您通过创建 XML 配置文件或进行 Jetpack WindowManager API 调用来确定应用如何显示其 activity(并排或堆叠)。
  • 系统会自动维护对小屏幕的支持。当应用在配备小屏幕的设备上时,activity 会相互堆叠。在大屏幕上,activity 会并排显示。系统会根据您已创建的配置(不需要分支逻辑)来确定呈现方式。
  • activity 嵌入支持设备屏幕方向的变化,并且可以在可折叠设备上无缝工作,该功能会随着设备折叠和展开而堆叠和取消堆叠 activity。

用途:

同时显示两个activity,跟随屏幕宽度改变(如折叠展开)自动相互堆叠或并排显示

运行时检查是否支持

SplitController.getInstance().isSplitSupported();

2.2 拆分窗口效果展示

A和B同时启动

全屏的A启动B,A和B并排显示

A、 B启动后,再启动C到右侧(类似应用多窗的导航模式)

A、 B启动后,再启动C此时B移到primary位置(类似应用多窗的购物模式)

A、 B启动后,再启动C,C全屏展示(可用于全屏播放视屏等)

2.3 适配指导

IDE版本要求

Android Studio Chipmunk | 2021.2.1 或更高版本

在应用的 build 文件中添加库依赖项

WindowManager 库和Jetpack Startup 库

implementation("androidx.window:window:1.1.0-alpha02")
implementation("androidx.startup:startup-runtime:1.1.1")

添加配置文件res/xml/main_split_config.xml

<resources
xmlns:window="http://schemas.android.com/apk/res-auto">
<SplitPairRule
window:splitRatio="0.5"
window:splitMinWidth="300dp">
<SplitPairFilter
window:primaryActivityName=".PrimaryAct"
window:secondaryActivityName=".Secondary1"/>
</SplitPairRule>
</resources>

AndroidManifest.xml添加InitializationProvider

备注:若提示找不到tools标签,需要添加xmlns

xmlns:tools="http://schemas.android.com/tools"

<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>

实现自己的嵌入加载器ExampleWindowInitializer

public class ExampleWindowInitializer implements Initializer<SplitController> {
@Override
public SplitController create(Context context) {
SplitController.initialize(context, R.xml.main_split_config);
return SplitController.getInstance();
}
@Override
public List<Class<? extends Initializer<?>>> dependencies() {
return emptyList();
}
}

运行app即可看到PrimaryAct与Secondary1左右并排显示

参数描述
SplitPairRule用来描述分屏配对情景(两侧容器均有具体activity),对应SplitPairFilter
splitRatio分屏比默认为0.5f,即左右1:1分屏
splitMinWidth默认为0建议配置600dp,意思是宽度达到600dp门限才可以分屏主窗口可分屏显示的最小窗口宽度
finishPrimaryWithSecondary取值”never” “always” “adjacent”,默认为nerver,always:若secondary container中所有activity都finish,则primary container中创建分屏的activity也会finish,不推荐应用主动配置此项。
finishSecondaryWithPrimary取值”never” “always” “adjacent”,默认为always,always:若primary container中所有activity都finish,则secondary container中所有activity也会finish,不推荐应用主动配置此项。
clearTop取值”true”或false默认为false true:启动activity窗口分屏,存在相同的primary container,若新建secondary container,则原secondary container中的activity会被finish掉,推荐应用配置,避免右分屏出现多实例
SplitPairFilter分屏配对关系(目前google仅支持枚举所有配对关系,不支持通配符)
primaryActivityName分屏的primay activity component name
secondaryActivityName分屏的secondary activity component name
secondaryActivityAction分屏的secondary activity 启动的action

SplitPlaceholderRule用来描述分屏下的占位符情景,对应ActivityFilter
placeholderActivityNameA启动B还没有启动此时placeholderActivityName对应的activity占据secondary位置
ActivityFilter适配该规则的activity
componentName组件名
intentActionintent
splitRatio分屏比默认为0.5f,即左右1:1分屏
splitMinWidth默认为0建议配置600dp,意思是宽度达到600dp门限才可以分屏主窗口可分屏显示的最小窗口宽度

ActivityRule用来特别需要全屏显示的特例activity,对应ActivityFilter
alwaysExpand取值”true”或false true:启动的activity全屏显示
ActivityFilter适配该规则的activity
componentName组件名
intentActionintent

深层链接分屏即平行视窗的导航模式(带占位符页面SplitPlaceholderRule)

<resources
xmlns:window="http://schemas.android.com/apk/res-auto">
<!-- Automatically split the following activity pairs. -->
<SplitPairRule
window:splitRatio="0.3"
window:splitMinWidth="600dp"
window:finishPrimaryWithSecondary="false"
window:finishSecondaryWithPrimary="true"
window:clearTop="true">
<SplitPairFilter
window:primaryActivityName=".MainActivity"
window:secondaryActivityName=".SecondActivity"/>
<SplitPairFilter
window:primaryActivityName=".MainActivity"
window:secondaryActivityName=".ThirdActivity"/>
<SplitPairFilter
window:primaryActivityName="*"
window:secondaryActivityName="*/*"
window:secondaryActivityAction="android.intent.action.VIEW"/>
</SplitPairRule>
<!-- Automatically launch a placeholder for the list activity. -->
<SplitPlaceholderRule
window:placeholderActivityName=".SplitActivityPlaceholder"
window:splitRatio="0.3"
window:splitMinWidth="600dp">
<ActivityFilter
window:activityName=".MainActivity"/>
</SplitPlaceholderRule>
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".FullScreenActivity"/>
</ActivityRule>
</resources>

比如在activity B 原位启动 activity C,并且没有额外的 intent 标志:

结果是同一任务中 activity 的叠置顺序如下:

导航模式是左侧固定主页,右侧堆叠二级、三级等子级页面。

多重分屏即购物模式

<resources xmlns:window="http://schemas.android.com/apk/res-auto">
<!-- Automatically split the following activity pairs. -->
<SplitPairRule
window:splitRatio="0.3"
window:splitMinWidth="600dp"
window:finishPrimaryWithSecondary="false"
window:finishSecondaryWithPrimary="true"
window:clearTop="true">
<SplitPairFilter
window:primaryActivityName=".MainActivity"
window:secondaryActivityName=".SecondActivity"/>
<SplitPairFilter
window:primaryActivityName=".MainActivity"
window:secondaryActivityName=".ThirdActivity"/>
<SplitPairFilter
window:primaryActivityName=".ThirdActivity"
window:secondaryActivityName="*/*"
window:secondaryActivityAction="android.intent.action.VIEW"/>
</SplitPairRule>
<!-- Automatically launch a placeholder for the list activity. -->
<SplitPlaceholderRule
window:placeholderActivityName=".SplitActivityPlaceholder"
window:splitRatio="0.3"
window:splitMinWidth="600dp">
<ActivityFilter
window:activityName=".MainActivity"/>
</SplitPlaceholderRule>
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".FullScreenActivity"/>
</ActivityRule>
</resources>

比如activity B 在侧面启动 activity C,并使分屏向一旁位移:

结果是同一任务中 activity 的叠置顺序如下:

购物模式左侧无固定主页。

新任务中的 activity

当分屏任务窗口中的 activity 启动新任务中的 activity 时,新任务将与包含分屏的任务分开并显示在全窗口中。“最近使用的应用”屏幕将显示两项任务:分屏中的任务和新任务。

从activity B启动新任务中的activity C。

有个限制,SplitPairFilter中不能有B|C配置规则

响应分屏状态变化

SplitInfo包含primary和secondary栈内容的变化

SplitController.getInstance().addSplitListener(this,
ContextCompat.getMainExecutor(this), new Consumer<List<SplitInfo>>() {
@Override
public void accept(List<SplitInfo> splitInfos) {
}
});

限制条件和注意事项

  • 不支持跨应用分屏
  • 所有Activity均需在同一Task中
  • 只能将同一进程中的 activity 组织和放置在分屏中
  • 关于应用orientation

若应用仅支持竖屏,则横屏时无法启动分屏,需要应用支持横屏,应用可根据屏幕长短边比例是否超过9/16来在onCreate和onConfigurationChanged中动态设定是否支持旋转屏还是仅支持竖屏

  • 支持resizeable

若配置android:resizeableActivity=“false”,会导致无法分屏显示

文档内容是否有帮助?
有帮助
无帮助