这个博客我们将讨论画中画模式,如何实现它以及如果有多个活动时如何管理后台堆栈。
现在,如果应用程序仅包含一个活动并且您必须实现 pip,这非常简单,您只需要将活动设为单一任务即可 这是代码片段-
<activity
android:name="HomeActivity"
android:launchMode="singleTask"
android:supportsPictureInPicture="true"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent. action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
覆盖 Home 活动中的 onUserLeaveHint 方法。
override fun onUserLeaveHint() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
if (!isInPictureInPictureMode) {
var pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
Logger.err(TAG, "onUserLeaveHintCalled")
var aspectRatio = Rational(ScreenUtils.getScreenWidth(this), ScreenUtils.getSceenHeight(this))
pictureInPictureParamsBuilder.setAspectRatio(aspectRatio).build()
enterPictureInPictureMode(pictureInPictureParamsBuilder.build())
}
}
如您所见,我们必须将我们的单个 Activity 作为单个任务,并为图中画提供支持。如果用户处于 pip 模式并且如果用户单击应用程序图标,则我们必须将我们的活动设置为 singleTask 背后的原因,将不会创建新任务,将重用相同的任务并将意图传递给onNewIntent(Intent intent) 方法。通过这种方式,我们可以在单个活动应用程序中实现 pip,因为我们不必在单个活动中维护后台堆栈。
现在,如果我们在应用程序中有多个 Activity,并且您想在进入 pip 后维护 backstack。
假设,我们有一个类似 Login -> VideoList -> VideoDetail -> VideoPlayer Activity 的场景。在达到 VideoPlayer 活动后,实际播放视频的活动并且当用户进入 pip 模式时,现在用户最大化它并离开 pip 然后单击后退按钮,用户直接进入另一个应用程序的主屏幕/上次打开的活动,但我们希望我们的用户转到我们播放 VideoPlay 的 Vod 详细信息页面。对于这种情况,我们必须遵循以下步骤-
1 - 在 VideoPlayer 活动的清单中添加 pip 支持。
2 - 将此活动启动模式设为 singleTask
3 - 为这个活动添加 Taskaffinity
4 - 从最近的 true 设置排除
<activity
android:name=".ui.videodetail.VodDetailActivity"
android:taskAffinity=".ui.videodetail.VodDetailActivity"
android:supportsPictureInPicture="true"
android:parentActivityName=".ui.dashboard.DashboardActivity"
android:launchMode="singleTask"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:resizeableActivity="true"
android:autoRemoveFromRecents="true"
android:excludeFromRecents="true"
android:allowTaskReparenting="true"
android:theme="@style/AppTheme.NoActionBar"
android:screenOrientation="portrait" />
如您所见,我已设置 taskAffinity 并设置 exclude from recent true 因为我们不想在 android 应用程序堆栈中显示两个任务。单任务启动模式和不同的亲和力将为 pip 启动一个新任务,我们必须从 android 应用程序堆栈中删除,因为我们不想为同一应用程序显示两个堆栈
现在如果用户点击这个视频播放器页面上的后退图标,首先我们要检查用户是否直接点击后退按钮而不进入 pip 模式,然后调用 super.finish(),但是如果 Activity 已经在pip 模式,然后我们必须检查 android 应用程序堆栈是否包含应用程序堆栈中您的应用程序的任务,然后我们必须在单击后退按钮时将该任务移到前面。代码为此 -
/**
* Bring up launcher task to front
*/
public static void navToLauncherTask(Context appContext) {
ActivityManager activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE);
// iterate app tasks available and navigate to launcher task (browse task)
assert activityManager != null;
final List<ActivityManager.AppTask> appTasks = activityManager.getAppTasks();
for (ActivityManager.AppTask task : appTasks) {
final Intent baseIntent = task.getTaskInfo().baseIntent;
final Set<String> categories = baseIntent.getCategories();
if (categories != null && categories.contains(Intent.CATEGORY_LAUNCHER)) {
task.moveToFront();
return;
}
}
}
通过这种方式,我们也可以使用管道模式维护后台堆栈,但这不是一个好习惯,如果您想为您的应用程序实现 pip,请尝试制作包含多个片段的单个活动应用程序。