如何在MVP中还原模型状态?

时间:2019-03-07 01:00:03

标签: android design-patterns model mvp model-view

应用说明

我正在尝试首次使用MVP实现Android应用,该应用会显示一条消息(从消息池中提取),并且当用户单击屏幕时会对其进行更改。显示所有消息后,该过程将重新开始(按照消息的相同顺序)。如果关闭或重新打开了该应用程序,则要求显示相同的消息。因此,我们必须在MVP模型中实现一些实现一些存储/恢复状态机制的机制。

这是该应用程序的基本演示:

enter image description here

MVP设计

我已为此应用实现了此MVP,如下所示:

  1. 模型负责什么,这将是下一条消息(它实现了应用程序状态)。
  2. 演示者决定何时询问下一条消息(以更新状态),具体取决于从用户(通过“视图”)接收到的事件。
  3. 视图决定如何显示,并显示来自用户(单击屏幕)的事件与演示者的消息。此外,由于视图也是MainActivity,因此请实例化 Presenter和Model实现。最后,它使用Parcelable 保存模型状态(作为onSaveInstanceState)(并恢复它)。

某些代码

(部分)视图实现:

class MainActivity : AppCompatActivity(), ViewMVC {

    private lateinit var presenter: Presenter
    private var model: Model? = CircularModel(LinkedList<State>(Arrays.asList(
            State("First"),
            State("Second"),
            State("Third")

    )))

    override fun onCreate(savedInstanceState: Bundle?) {
        if (savedInstanceState != null) {
            model = savedInstanceState.getParcelable("model")
        }

        presenter = PresenterImpl(this, model!!)
    }

    override fun onSaveInstanceState(outState: Bundle?) {
        outState?.putParcelable("model", model!!)
        super.onSaveInstanceState(outState)
    }

(部分)模型实现:

@Parcelize
class CircularModel constructor(var states: @RawValue Deque<State>?) : Model, Parcelable {

    override fun getModelState(): State {
        return states!!.peekFirst()
    }

    override fun getModelNextState(): State {
        // Black magic happening here!
        return getModelState()
    }
}

问题/我的问题

由于Presenter和Model应该是“ Android不可知的”,因此View会注意保存应用状态(即Model对象)。但是,这打破了视图不知道模型的原理。 我的问题是:如何在不了解View实际实现的情况下保存Model对象?在这种情况下,处理Model状态的最佳方法是什么?

一个实际的解决方案可能是编写代码以在模型本身中序列化模型,并为每个getNextState()保存,但这将意味着在模型中使用Android调用(并降低其可测试性)。

1 个答案:

答案 0 :(得分:1)

您应该使用其他持久性机制。 onSaveInstanceState()确实用于操作系统由于配置/方向更改等原因需要还原UI状态的情况。这不是通用的存储机制。

该模型是持久保存数据的正确位置,并且您应该尽可能使模型与Android无关,这是正确的。您可以做的是定义一个代表您的持久性要求的接口:

interface SampleRepo{ 
   fun saveData(...)
   fun getData(...)
}

然后您在类中首选的持久性机制(例如SharedPreferences,SQlite等)将实现该接口。这是隐藏您的Android专用内容的地方。

class SharedPrefRepo : SampleRepo{
   override fun saveData(...)
   override fun getData(...)
}

理想情况下,您需要某种注入机制,以便可以将上述实例注入模型类(例如Dagger)。它需要更多的管道代码,但这就是松耦合的代价。对于更简单的应用程序(例如您正在执行的操作),所有这些都是过分的。但是,如果您要研究适当的Android应用程序架构和松散耦合,那么值得探索如何正确进行。