前言
从 Android 7.0 开始,Google 推出了一个名为“多窗口模式”的新功能,允许在设备屏幕上同时显示多个应用,多窗口模式允许多个应用同时共享同一屏幕,多窗口模式(Multi Window Supports)目前支持以下三种配置:
一、分屏模式的适配
1、我们如何才能让自己的 APP 支持分屏模式呢?
若项目的targetSDKVersion 大于等于24,那么可以在AndroidManifest.xml 文件的Application 或Activity 节点通过设置android:resizeableActivity=[“true” | “false”] 来控制整个 APP 或某个 Activity 是否支持分屏。该属性的默认值是true ,也就是说,如果不设置该属性,在支持分屏的设备上,默认是可以分屏的。
若项目的targetSDKVersion 小于24,那么运行在支持分屏的设备上,默认可以分屏。这时如果需要禁止分屏,需要在AndroidManifest.xml 文件的Application 或Activity 节点设置android:screenOrientation 属性来控制整个 APP 或 某个 Activity 的屏幕方向,从而控制整个 APP 或某个 Activity 禁止分屏。
2、分屏模式的监听
能不能在代码中监听 APP 是否进入分屏模式呢?答案是能。由于 APP 在分屏模式发生改变时会执行onMultiWindowModeChanged 方法,因此我们在 Activity 中重写这个方法就可以实现分屏的监听了。
@Override
public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
super.onMultiWindowModeChanged(isInMultiWindowMode);
// 判断当前是否为分屏模式
if (isInMultiWindowMode) {
// 已进入分屏模式
} else {
// 未进入分屏模式
}
}
3、分屏模式下的生命周期
- 进入分屏模式时,Activity 的生命周期:
onPause()- onStop()- onMultiWindowModeChanged()- onDestroy()- onCreate()- onStart()- onResume()- onPause()
- 退出分屏模式时,Activity 的生命周期:
onStop()- onDestroy()- onCreate()- onStart()- onResume()- onPause()- onMultiWindowModeChanged()- onResume()
可以看出,在进入分屏模式时,Activity 先执行onMultiWindowModeChanged 方法,再重建自己。在退出分屏模式时,Activity 先重建自己,再执行onMultiWindowModeChanged 方法。这样会有一个问题,我们的 APP 进入分屏模式时,在onMultiWindowModeChanged 方法中如果有对 UI 等的操作,经过之后的自动重建就没有效果了。为了防止这种情况,需要在AndroidManifest.xml 的Activity 节点设置以下属性:
android:configChanges=“screenSize|smallestScreenSize|screenLayout|orientation”
设置了这个属性,在进入分屏模式时,Activity 就不会自动重建了。
- 分屏模式下打开 Activity
如果 APP 在分屏模式下打开 Activity 时,为 Intent 设置了Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT 和Intent.FLAG_ACTIVITY_NEW_TASK 标志,那么新打开的 Activity 将显示在当前 APP 的另一侧。例如下面的代码:
Intent intent = new Intent(this, NewActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
二、多窗口模式在Activity和ActivityThread类中的主要调用回溯
1、结合前面的分析,可以发现onMultiWindowModeChanged是一个很重要的方法,让我们来看下这个方法是什么时候被系统调用的。
framewroks/base/core/java/android/app/Activity.java
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback,
AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
private Window mWindow;//Activity对应的Window
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
private boolean mIsInMultiWindowMode;//当前是否处于多窗口模式
@Deprecated
public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
}
public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {
onMultiWindowModeChanged(isInMultiWindowMode);
}
final void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode,
Configuration newConfig) {
if (DEBUG_LIFECYCLE) Slog.v(TAG,
"dispatchMultiWindowModeChanged " + this + ": " + isInMultiWindowMode
+ " " + newConfig);
mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode, newConfig);
if (mWindow != null) {
mWindow.onMultiWindowModeChanged();
}
mIsInMultiWindowMode = isInMultiWindowMode;
onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
}
}
onMultiWindowModeChanged方法在Activity中被初次调用,是在dispatchMultiWindowModeChanged方法中。
2、而Activity的dispatchMultiWindowModeChanged方法初次被调用,是在ActivityThread类中。
framewroks/base/core/java/android/app/ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler
implements ActivityThreadInternal {
private final Map<IBinder, Integer> mLastReportedWindowingMode = Collections.synchronizedMap(
new ArrayMap<>());
//启动Activity的核心方法
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...代码省略...
Activity activity = null;
java.lang.ClassLoader cl = appContext.getClassLoader();
//通过反射创建Activity实例对象
activity = mInstrume