前言

从 Android 7.0 开始,Google 推出了一个名为“多窗口模式”的新功能,允许在设备屏幕上同时显示多个应用,多窗口模式允许多个应用同时共享同一屏幕,多窗口模式(Multi Window Supports)目前支持以下三种配置:

  • 分屏模式:让系统可以左右或上下并排显示应用。

  • 画中画模式:在应用中用小窗口叠加显示其他应用

  • 自由窗口模式:在可移动且可调整大小的单独窗口中显示各个应用。

本系列文章我们主要来分析一下分屏模式相关的知识点。

分屏模式案例

资源配置文件

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <!-- 关键配置:启用分屏并处理配置变更 -->
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTask"
            android:resizeableActivity="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

        </activity>

        <!-- 第二个Activity用于分屏测试 -->
        <activity android:name=".SecondActivity" />
    </application>

</manifest>

布局文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_status"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFFF00"
        android:gravity="center"
        android:padding="100dp"
        android:text="主页处于全屏"
        android:textSize="30sp"
        android:textStyle="bold" />

    <Button
        android:id="@+id/btn_open_second"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="打开第二个页面" />
</LinearLayout>

布局文件activity_second.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFFF00"
        android:gravity="center"
        android:padding="100dp"
        android:text="第二个页面"
        android:textSize="30sp"
        android:textStyle="bold" />
</LinearLayout>

项目源码

MainActivity.java

public class MainActivity extends Activity {

    private static final String TAG = "TestMainActivity";
    private TextView mTvStatus;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG, "onCreate: ");
        setContentView(R.layout.activity_main);
        mTvStatus = findViewById(R.id.tv_status);
        findViewById(R.id.btn_open_second).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
            }
        });
    }


    // 恢复输入内容
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.i(TAG, "onRestoreInstanceState: ");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG, "onStart: ");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, "onResume: ");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, "onPause: ");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, "onStop: ");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy: ");
    }

    // 监听分屏模式变化
    @Override
    public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
        super.onMultiWindowModeChanged(isInMultiWindowMode);
        Log.i(TAG, "onMultiWindowModeChanged: isInMultiWindowMode = " + isInMultiWindowMode);
        mTvStatus.setText(isInMultiWindowMode ? "当前处于分屏模式" : "当前处于全屏模式");
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.i(TAG, "onConfigurationChanged: ");
    }
}

SecondActivity.java

public class SecondActivity extends Activity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }

}

从最近任务触发分屏模式

打开MainActivity,然后进入最近任务触发分屏,可以成功进入分屏模式,具体可以参考下图。
最近任务进入分屏

以分屏模式打开一个新的Activity

点击MainActivity的页面的按钮,以分屏方式打开SecondActivity,也可以进入分屏模式。
以分屏模式打开页面

分屏模式的适配

配置AndroidManifest.xml

若项目的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 禁止分屏。

以分屏模式打开新的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);

分屏模式的监听

能不能在代码中监听 APP 是否进入分屏模式呢?答案当然是能。由于 APP 在分屏模式发生改变时会执行onMultiWindowModeChanged 方法,因此我们在 Activity 中重写这个方法,通过这个方法就可以实现分屏的监听了。

@Override
 public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
  super.onMultiWindowModeChanged(isInMultiWindowMode);
  // 判断当前是否为分屏模式
  if (isInMultiWindowMode) {
   // 已进入分屏模式
  } else {
   // 未进入分屏模式
  }
 }

防止UI自动重建

默认情况下当Activity发生分屏和全屏场景切换的时候,进入分屏模式时,onCreate方法会被重新调用导致UI重建。为了防止这种情况,可以在AndroidManifest.xml 的Activity 节点设置以下属性:

android:configChanges=“screenSize|smallestScreenSize|screenLayout|orientation”

设置了这个属性,在进入分屏模式时,onCreate方法就不会会被重新调用,Activity也不会重建了。

分屏模式下的生命周期

configChanges未添加防重建属性

  • 进入分屏模式时,Activity 的生命周期:

onPause()- onStop()- onSaveInstanceState()- onDestroy()- onCreate()- onStart()- onRestoreInstanceState()- onResume()

  • 退出分屏模式时,Activity 的生命周期:

onPause()- onStop()- onSaveInstanceState()- onDestroy()- onCreate()- onStart()- onRestoreInstanceState()- onResume()

configChanges添加防重建属性

  • 进入分屏模式时,Activity 的生命周期:

onPause()- onMultiWindowModeChanged()- onConfigurationChanged()- onResume()

  • 退出分屏模式时,Activity 的生命周期:

onMultiWindowModeChanged()- onConfigurationChanged()

💡 技术无价,赞赏随心

写文不易,如果本文帮你避开了“八小时踩坑”,或者让你直呼“学到了!”
欢迎扫码赞赏,让我知道这篇内容值得!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐