原文:REACTIVE APPS WITH MODEL-VIEW-INTENT - PART6 - RESTORING STATE
做者:Hannes Dorfmann
译者:却把清梅嗅android
在前几篇文章中,咱们讨论了Model-View-Intent(MVI)
和单向数据流的重要性,这极大简化了状态的恢复,那么其过程和原理是什么呢,本文咱们针对这个问题进行探讨。git
咱们将针对2个场景进行探讨:github
Bundle
中获取以前在Activity.onSaveInstanceState()
保存的状态)这种状况处理起来很是简单。咱们只须要保持咱们的RxJava
流随着时间的推移从Android
生命周期组件(即Activity
,Fragment
甚至ViewGroups
)种发射新的状态。缓存
好比Mosby
的 MviBasePresenter
类在内部就使用了相似这样的RxJava
的流:使用 PublishSubject 发射intent
,以及使用 BehaviorSubject 对View
进行渲染。对此,在 第二部分 中我已经阐述了是如何实现的。其主要思想是MviBasePresenter
是一个和View
生命周期隔离的组件,所以它可以被View
脱离和附着。在Mosby
中,当View
被永久销毁时,Presenter
被destroyed
(垃圾收集)。一样,这只是Mosby
的一个实现细节,您的MVI实现可能彻底不一样。网络
重要的是,像Presenter
这样的组件存活在View
的生命周期以外,由于这样很容易处理View
脱离和附着的事件。每当View
(从新)依附到Presenter
时,咱们只需调用view.render(previousState)
(所以Mosby内部使用了BehaviorSubject
)。app
这只是处理屏幕方向改变的一种处理方案,它一样适用于返回栈导航中。例如,Fragment
在返回栈中,咱们若是从返回栈中返回,咱们能够简单的再次调用view.render(previousState)
,而且,view
也会显示正确的状态。ide
事实上,即便没有View
对其进行依附,状态也依然会被更新,由于Presenter
存活在View
的生命周期以外,并被保存在RxJava
流中。设想若是没有View
附着,则会收到一个更改数据(部分状态)的推送通知,一样,每当View
从新附着时,最新状态(包含来自推送通知的更新数据)将被移交给View
进行渲染。函数
这种场景在MVI
这种单向数据流模式下也很简单。如今咱们但愿View
层的状态不只仅存在于内存中,即便进程终止也可以对其持有。Android
中一般的一种解决方案是经过调用Activity.onSaveInstanceState(Bundle)
去保存状态。学习
与MVP
、MVVM
不一样的是,在MVI
中你持有了表明状态的Model
,View
有一个render(state)
方法来记录最新的状态,这让持有最后一个状态变得简单。所以,显然易见的是打包和存储状态到一个bundle
下面,而且以后恢复它:spa
class MyActivity extends Activity implements MyView {
private final static KEY_STATE = "MyStateKey";
private MyViewState lastState;
@Override
public void render(MyState state) {
lastState = state;
... // 更新UI控件
}
@Override
public void onSaveInstanceState(Bundle out){
out.putParcelable(KEY_STATE, lastState);
}
@Override
public void onCreate(Bundle saved){
super.onCreate(saved);
MyViewState initialState = null;
if (saved != null){
initialState = saved.getParcelable(KEY_STATE);
}
presenter = new MyPresenter( new MyStateReducer(initialState) ); // With dagger: new MyDaggerModule(initialState)
}
...
}
复制代码
我想你已得要领,请注意,在onCreate()
中咱们并不直接调用view.render(initialState)
, 咱们让初始状态的逻辑下沉到状态管理的地方: 状态折叠器(请参考第三部分),咱们将它与.scan(initialState,reducerFunction)
搭配使用。
与其余模式相比,使用单向数据流和表示状态的Model
,许多与状态相关的东西更容易实现。可是,我一般不会在个人App
中将状态持久化,两个缘由:首先,Bundle
有大小限制,所以你不能将任意大的状态放入bundle
中(或者你能够将状态保存到文件或像Realm
这样的对象存储中);其次,咱们只讨论了如何序列化和反序列化状态,但这不必定与恢复状态相同。
例如:假设咱们有一个LCE
(加载内容错误)视图,它会在加载数据时显示一个指示器,并在完成加载后显示条目列表,所以状态就相似MyViewState.LOADING
。让咱们假设加载须要一些时间,而就在此时进程恰好被终止了(好比忽然一个电话打了进来,致使电话应用占据了前台)。
若是咱们仅仅将MyViewState.LOADING
进行序列化并在以后进行反序列化操做对状态进行恢复,咱们的状态折叠器会调用view.render(MyViewState.LOADING)
,目前为止这是正确的,但实际上咱们 永远不会经过这个状态对网络进行请求加载数据。
如您所见,序列化和反序列化状态与状态恢复不一样,这可能须要一些额外的步骤来增长复杂性(固然对于MVI
来讲这实现起来一样比其它模式更简单),当从新建立View
时,包含某些数据的反序列化状态可能会过期,所以您可能必须刷新(加载数据)。
在我研究过的大多数应用程序中,我发现相比之下这种方案更简单且友好:即,将状态仅仅保存在内存中,而且在进程死亡后以空的初始状态启动,好像应用程序将首次启动同样。理想状况下,App
具备对缓存和离线的支持,所以在进程终止后加载数据的速度也会很快。
这最终致使了我和其它Android
开发者针对一个问题进行了激烈的辩论:
若是我使用缓存或存储,我已经拥有了一个存活于
Android
组件生命周期以外的组件,并且我再也不须要去处理相关的状态存储问题,而且MVI
毫无心义,对吗?
这其中大多数Android
开发者推荐 Mike Nakhimovich
发表的 《Presenter 不是为了持久化》这篇文章介绍的 NyTimes Store,这是一个数据加载和缓存库。遗憾的是,那些开发人员不明白 加载数据和缓存不是状态管理。例如,若是我必须从缓存或存储中加载数据呢?
最后,相似NyTimes Store的库帮助咱们处理进程终止了吗?显然没有,由于进程随时都有可能被终止。咱们能作的仅仅是祈祷Android
操做系统不要杀死咱们的进程,由于咱们还有一些须要经过Service
作的事(这也是一个可以不生存于其它android组件生命周期的组件),或者咱们能够经过使用RxJava
而再也不须要Android Service
了,这可行吗?
咱们将在下一章节探讨关于android services
、RxJava
以及MVI
,敬请期待。
《使用MVI打造响应式APP》原文
《使用MVI打造响应式APP》译文
《使用MVI打造响应式APP》实战
Hello,我是却把清梅嗅,若是您以为文章对您有价值,欢迎 ❤️,也欢迎关注个人博客或者Github。
若是您以为文章还差了那么点东西,也请经过关注督促我写出更好的文章——万一哪天我进步了呢?