就像 Guide to App Architecture(应用架构指南) 里说的那样,大多数 APP 有多个数据源,比如:
- 远程:网络、云端
- 本地:数据库、文件
- 内存中的缓存
在应用中放一个数据层是一个好主意,数据层完全不关心展示层(MVP
中的 P
)。由于保持缓存和数据库与网络同步的算法通常很琐碎复杂,所以建议为每个仓库创建一个类作为处理同步的单一入口。
如果是许多种并且差别很大的数据模型,考虑使用多个数据仓库。
✅ 添加数据仓库作为数据访问的单一入口。
关于数据状态
考虑一下这种情况:你正在观察一个 ViewModel 暴露出来的 LiveData,它包含了一个待显示数据的列表。视图层该如何区分被加载的数据,网络错误和空列表呢?
- 你可以从 ViewModel 中暴露出一个
LiveData<MyDataState>
。MyDataState
可能包含数据是正在加载还是已经加载成功、失败的信息。
可以将类中有状态和其他元数据(比如错误信息)的数据封装到一个类。参见示例代码中的 Resource 类。
✅ 使用一个包装类或者 LiveData 来暴露状态信息。
保存 Activity 的状态
Activity 的状态是指在 Activity 消失时重新创建屏幕内容所需的信息,Activity 消失意味着被销毁或进程被终止。旋转屏幕是最明显的情况,我们已经在 ViewModel 部分提到了。保存在 ViewModel 的状态是安全的。
但是,你可能需要在其他 ViewModel 也消失的场景中恢复状态。例如,当操作系统因资源不足杀死进程时。
为了高效地保存和恢复 UI 状态,组合使用 onSaveInstanceState()
和 ViewModel。
这里有个示例:ViewModels: Persistence, onSaveInstanceState(), Restoring UI State and Loaders
事件
我们管只发生一次的操作叫做事件。 ViewModels 暴露数据,但对于事件怎么样呢?例如,导航事件或显示 Snackbar 消息等应该仅被执行一次的操作。
事件的概念并不能和 LiveData 存取数据的方式完美匹配。来看下面这个从 ViewModel 中取出来的字段:
LiveData snackbarMessage = new MutableLiveData<>();
一个 Activity 开始观察这个字段,ViewModel 完成了一个操作,所以需要更新消息:
snackbarMessage.setValue(“Item saved!”);
显然,Activity 接收到这个值后会显示出来一个 SnackBar。
但是,如果用户旋转手机,则新的 Activity 被创建并开始观察这个字段。当对 Li