三星一直着眼于未来,在科技的领域不断探索,自去年 Samsung Galaxy Fold 上市以来,已有三款折叠机问世,在一代又一代产品的创新中,展现了手机外形新的趋势。在 Galaxy Fold 中,我们希望更大的屏幕可以让用户利用多窗口同时执行更多任务、一心多用,手机内外屏切换拥有连续性、自由切换。那么为了给用户带来无缝衔接、状态一致的体验,在多窗口和手机内外屏切换过程中,应用应保持界面的连续性、保留数据和状态。
多窗口和内外屏切换举例
1)在折叠屏内屏中,浏览网页或者阅读电子书,打开多窗口,用户的预期肯定是当前浏览的网页位置保持不变,或者电子书的章节和浏览位置保持不变。

2) 同样,在内屏中浏览网页切换到外屏,或者从外屏切换到内屏,当前浏览的页面仍然要保持一致性和连续性,包括 Tab 位置和页面中的位置。

3) 在应用搜索输入框中,用户输入了内容,这个时候无论是打开多窗口还是内外屏切换,输入的内容不能丢失。

4) 在音视频类应用中,当正在播放音乐或者视频时,打开多窗口或者内外屏切换,不仅需要保持正在播放的位置,还需要恢复播放状态。比如正在播放视频的时候,打开多窗口,视频应可以继续播放。

系统在多窗口转换或是内外屏切换时会触发配置变更,就像选择屏幕、切换语言触发配置变更一样,应用需要按照不同情况处理配置变更。可以采用系统默认的方法处理配置变更,也可以自行处理配置变更,下面介绍这两种方法。
1.运行时配置变更 - 系统默认
默认情况下,Activity 因为配置变更会被销毁重建,应用需要保存和恢复界面的数据和状态。Android 提供 onSaveInstanceState() 方法、ViewModel 对象和本地存储空间三种保存界面状态的方法,应用可以根据界面数据的复杂程度、应用的场景和性能将这些方法组合使用,为用户提供合理顺畅的界面。

1.1 onSaveInstanceState() 方法
对于简单的数据,Activity 可以使用 onSaveInstanceState() 方法在 onCreate() 或 onRestoreInstanceState() 中恢复数据。因为 onSavedInstanceState() 会将数据序列化到磁盘,如果序列化的对象很复杂,会占用大量的内存。而且这个过程发生在主线程上,如果耗时太长,可能会导致卡顿。所以 onSaveInstanceState() 仅适用于轻量级数据,另外,onSaveInstanceState() 最重要的用途是可以应对被系统杀掉的情况。
代码举例:
在 onSaveInstanceState() 中保存数据:
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, currentScore);
savedInstanceState.putInt(STATE_LEVEL, currentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
在 onCreate() 中恢复数据:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
currentScore = savedInstanceState.getInt(STATE_SCORE);
currentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
// ...
}
参考 Android 官网:
https://developer.android.google.cn/guide/components/activities/activity-lifecycle.html
1.2 ViewModel
ViewModel 是 Android Jetpack 的一个类,它可以在 Activity Fragment 生命周期内存储和管理 UI 界面相关的数据。将界面控制逻辑和数据管理分离开的方式更简便更高效,也有利于代码后期维护。
下图是 Activity 经历屏幕旋转后生命周期状态和 ViewModel 的生命周期,屏幕尺寸等配置变更同理。一般在系统首次调用 Activity 对象的 onCreate() 方法时请求 ViewModel,ViewModel 存在的时间范围是从首次请求 ViewModel 直到 Activity 销毁。Activity 因为配置变更被销毁重建,而 ViewModel 不会被销毁,直到 Activity Finished 才会被销毁。

代码举例:
创建一个 ViewModel 类负责界面数据,在配置变更后,保存数据:
public class UserModel extends ViewModel {
private final MutableLiveData userLiveData = new MutableLiveData<>();
public LiveData getUser() {
return userLiveData;
}
public UserModel() {
// trigger user load.
}
void doAction() {
// depending on the action, do necessary business logic calls and update the
// userLiveData.
}
}
在 Activity onCreate() 中通过
ViewModelProvider 获取数据:
public class UserActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_activity_layout);
final UserModel viewModel = new ViewModelProvider(this).get(UserModel.class);
viewModel.getUser().observe(this, new Observer() {
@Override
public void onChanged(@Nullable User data) {
// update ui.
}
});
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewModel.doAction();
}
});
}
}
参考 Android 官网:
https://developer.android.google.cn/reference/androidx/lifecycle/ViewModel
1.3 持久性存储
应用处理多窗口和开合折叠机保持界面状态时比较适合使用 ViewModel 和 onSaveInstanceState() 这些机制来暂时存储瞬时界面状态。但 ViewModel 和 onSaveInstanceState() 均不是长期存储解决方案,所以不能替代本地存储空间,例如数据库。对于复杂或大型应用数据,应用可以使用 Room 将数据保存到本地数据库。
Room 是在 SQLite 的基础上提供了一个抽象层,让开发者可以便捷访问 SQLite 数据库。如需了解 Room 的详细介绍,请查看 Android 官网:
https://developer.android.google.cn/training/data-storage/room?hl=zh_cn
四. 自行处理配置变更
应用也可以选择不重启自行处理配置变更,应用声明 Activity 自行处理配置变更后,将阻止系统重启 Activity,应用自行调整界面。
声明自行处理配置变更的方法:
在 manifest 文件中 标签里添加 android:configChanges 属性,并至少包含 screenSize|smallestScreenSize|screenLayout 配置值。
代码示例:
android:configChanges="screenSize|smallestScreenSize|screenLayout ">
当配置变更时,Activity 会接收到 onConfigurationChanged() 的调用消息。此方法会收到传递的 Configuration 对象,从而获得新设备配置,比如屏幕的分辨率信息。调用此方法时,Activity 的 Resources 对象会相应地进行更新,并根据新配置返回资源,以便在系统不重启 Activity 的情况下轻松重置界面元素。应用应根据新的分辨率信息调整布局,恢复页面数据。
参考资料
https://developer.android.google.cn/guide/topics/resources/runtime-changes
https://developer.android.google.cn/topic/libraries/architecture/saving-states
https://developer.android.google.cn/topic/libraries/architecture/viewmodel
https://developer.samsung.com/galaxy-fold/app-continuity.html
联系我们
如果您在适配过程中遇到了技术问题,对折叠屏适配有任何建议或意见:
欢迎发邮件到:rdtpservice@samsung.com
邮件主题:三星折叠屏适配 +APP 名
感谢您的关注和参与!


↙↙↙阅读原文可查看相关链接,并与作者交流