How to restore Model state in MVP?What are MVP and MVC and what is the difference?How do save an Android Activity state using save instance state?Why is the Android emulator so slow? How can we speed up the Android emulator?Restore State after process is killedWhy should I override onSavedInstanceState for retrieve instance state in android?MVP Android - Where to save the view state?Tensorflow: how to save/restore a model?Pass bundle intent in android using MVPWhat is the best way to restore state in MVP?restoring state in a presenter with MVP
Should I warn a new PhD Student?
Why is implicit conversion not ambiguous for non-primitive types?
Do native speakers use "ultima" and "proxima" frequently in spoken English?
How would a solely written language work mechanically
Center page as a whole without centering each element individually
Weird lines in Microsoft Word
Is there a distance limit for minecart tracks?
Sort with assumptions
How to get directions in deep space?
What is the period/term used describe Giuseppe Arcimboldo's style of painting?
Using an older 200A breaker panel on a 60A feeder circuit from house?
What is the purpose of using a decision tree?
What (if any) is the reason to buy in small local stores?
Rendered textures different to 3D View
Make a Bowl of Alphabet Soup
What properties make a magic weapon befit a Rogue more than a DEX-based Fighter?
What is the meaning of "You've never met a graph you didn't like?"
I keep switching characters, how do I stop?
Derivative of an interpolated function
Why do Radio Buttons not fill the entire outer circle?
Reasons for having MCU pin-states default to pull-up/down out of reset
How to preserve electronics (computers, ipads, phones) for hundreds of years?
A seasonal riddle
Would this string work as string?
How to restore Model state in MVP?
What are MVP and MVC and what is the difference?How do save an Android Activity state using save instance state?Why is the Android emulator so slow? How can we speed up the Android emulator?Restore State after process is killedWhy should I override onSavedInstanceState for retrieve instance state in android?MVP Android - Where to save the view state?Tensorflow: how to save/restore a model?Pass bundle intent in android using MVPWhat is the best way to restore state in MVP?restoring state in a presenter with MVP
App Descripion
I'm trying to implement for my first time an Android app with MVP, where a message (taken from a pool of messages) is displayed and it's changed when the user click on the screen. Once all message have been displayed, the process will start over (following the same order of messages). A requirement is to display the same message if the app is closed/reopened. So, we have to implement some implement some store/restore state mechanism in the MVP model.
Here's a basic demo of the app:
MVP Design
I've implemented this MVP for this app as follow:
- The Model takes care of what it will be the next message (it implements the application state).
- The Presenter decides when to ask for the next message (to update the state), depending on the received events from the user (through the View).
- The View decides how to show the actual message and communicates events from the user (clicks on the screen) to the presenter. In addition, since the View is also the
MainActivity
, it takes care to instantiate the Presenter and Model implementations. Finally, it saves the Model state (as aParcelable
) withonSaveInstanceState
(and also restores it).
Some Code
(Partial) View implementation:
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)
(Partial) Model implementation:
@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()
The Problem / My question
Since Presenter and Model should be "Android agnostic", saving the app state (i.e., the Model object) is taken care by the View. However, this breaks the principle where the View doesn't know the Model. My question is: how to save the Model object, without the View knowing the actual implementation of it? What is the best way to deal with the Model state in this scenario?
An actual solution could be to write the code to serialize the Model in the Model itself and save it for each getNextState()
, but this would mean use Android calls in the Model (and reduce its testability).
android design-patterns model mvp model-view
add a comment |
App Descripion
I'm trying to implement for my first time an Android app with MVP, where a message (taken from a pool of messages) is displayed and it's changed when the user click on the screen. Once all message have been displayed, the process will start over (following the same order of messages). A requirement is to display the same message if the app is closed/reopened. So, we have to implement some implement some store/restore state mechanism in the MVP model.
Here's a basic demo of the app:
MVP Design
I've implemented this MVP for this app as follow:
- The Model takes care of what it will be the next message (it implements the application state).
- The Presenter decides when to ask for the next message (to update the state), depending on the received events from the user (through the View).
- The View decides how to show the actual message and communicates events from the user (clicks on the screen) to the presenter. In addition, since the View is also the
MainActivity
, it takes care to instantiate the Presenter and Model implementations. Finally, it saves the Model state (as aParcelable
) withonSaveInstanceState
(and also restores it).
Some Code
(Partial) View implementation:
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)
(Partial) Model implementation:
@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()
The Problem / My question
Since Presenter and Model should be "Android agnostic", saving the app state (i.e., the Model object) is taken care by the View. However, this breaks the principle where the View doesn't know the Model. My question is: how to save the Model object, without the View knowing the actual implementation of it? What is the best way to deal with the Model state in this scenario?
An actual solution could be to write the code to serialize the Model in the Model itself and save it for each getNextState()
, but this would mean use Android calls in the Model (and reduce its testability).
android design-patterns model mvp model-view
add a comment |
App Descripion
I'm trying to implement for my first time an Android app with MVP, where a message (taken from a pool of messages) is displayed and it's changed when the user click on the screen. Once all message have been displayed, the process will start over (following the same order of messages). A requirement is to display the same message if the app is closed/reopened. So, we have to implement some implement some store/restore state mechanism in the MVP model.
Here's a basic demo of the app:
MVP Design
I've implemented this MVP for this app as follow:
- The Model takes care of what it will be the next message (it implements the application state).
- The Presenter decides when to ask for the next message (to update the state), depending on the received events from the user (through the View).
- The View decides how to show the actual message and communicates events from the user (clicks on the screen) to the presenter. In addition, since the View is also the
MainActivity
, it takes care to instantiate the Presenter and Model implementations. Finally, it saves the Model state (as aParcelable
) withonSaveInstanceState
(and also restores it).
Some Code
(Partial) View implementation:
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)
(Partial) Model implementation:
@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()
The Problem / My question
Since Presenter and Model should be "Android agnostic", saving the app state (i.e., the Model object) is taken care by the View. However, this breaks the principle where the View doesn't know the Model. My question is: how to save the Model object, without the View knowing the actual implementation of it? What is the best way to deal with the Model state in this scenario?
An actual solution could be to write the code to serialize the Model in the Model itself and save it for each getNextState()
, but this would mean use Android calls in the Model (and reduce its testability).
android design-patterns model mvp model-view
App Descripion
I'm trying to implement for my first time an Android app with MVP, where a message (taken from a pool of messages) is displayed and it's changed when the user click on the screen. Once all message have been displayed, the process will start over (following the same order of messages). A requirement is to display the same message if the app is closed/reopened. So, we have to implement some implement some store/restore state mechanism in the MVP model.
Here's a basic demo of the app:
MVP Design
I've implemented this MVP for this app as follow:
- The Model takes care of what it will be the next message (it implements the application state).
- The Presenter decides when to ask for the next message (to update the state), depending on the received events from the user (through the View).
- The View decides how to show the actual message and communicates events from the user (clicks on the screen) to the presenter. In addition, since the View is also the
MainActivity
, it takes care to instantiate the Presenter and Model implementations. Finally, it saves the Model state (as aParcelable
) withonSaveInstanceState
(and also restores it).
Some Code
(Partial) View implementation:
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)
(Partial) Model implementation:
@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()
The Problem / My question
Since Presenter and Model should be "Android agnostic", saving the app state (i.e., the Model object) is taken care by the View. However, this breaks the principle where the View doesn't know the Model. My question is: how to save the Model object, without the View knowing the actual implementation of it? What is the best way to deal with the Model state in this scenario?
An actual solution could be to write the code to serialize the Model in the Model itself and save it for each getNextState()
, but this would mean use Android calls in the Model (and reduce its testability).
android design-patterns model mvp model-view
android design-patterns model mvp model-view
edited Mar 7 at 1:13
justHelloWorld
asked Mar 7 at 1:00
justHelloWorldjustHelloWorld
2,26221757
2,26221757
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
You should use a different persistence mechanism. The onSaveInstanceState() is really used for situations where the OS needs to restore UI state because of things like configuration / orientation changes. It's not a general purpose storage mechanism.
The model is the correct place to persist data and it is correct that you should try to keep the model as Android agnostic as possible. What you can do is define an interface that represents your persistence requirements:
interface SampleRepo
fun saveData(...)
fun getData(...)
Then your preferred persistence mechanism (e.g. SharedPreferences, SQlite etc.) in a class implements that interface. This is where your Android specific stuff will be hidden.
class SharedPrefRepo : SampleRepo
override fun saveData(...)
override fun getData(...)
Ideally you'll want some injection mechanism so you can inject an instance of the above to your model class (e.g. Dagger). It requires some more plumbing code, but that is the price of loose coupling. For a simpler app, like what you're doing, all of this is overkill. But if you're trying to study proper Android app architecture and loose coupling then it's worth exploring how to do it properly.
Thank you Eugene for your answer, I find it a very good solution. I still have some questions: 1. Every call toSampleRepo
call will be performed inCircularModel
model (the Model implementation), right? 2. When should we callsaveData
? At everygetModelNextState()
? Or only when we exit from the app?
– justHelloWorld
Mar 7 at 8:06
1) - yes, correct. The Repo class will be inside the Model class. 2) - In this particular case I'd probably save it only when app exits or goes into background. But a real world implementation might want to keep such data constantly in sync so important state changes are persisted as soon as they happen. If your app crashed for example while it's doing something else and you only save when app goes to background then app might get restored with outdated data.
– Eugene
Mar 7 at 8:39
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55034496%2fhow-to-restore-model-state-in-mvp%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You should use a different persistence mechanism. The onSaveInstanceState() is really used for situations where the OS needs to restore UI state because of things like configuration / orientation changes. It's not a general purpose storage mechanism.
The model is the correct place to persist data and it is correct that you should try to keep the model as Android agnostic as possible. What you can do is define an interface that represents your persistence requirements:
interface SampleRepo
fun saveData(...)
fun getData(...)
Then your preferred persistence mechanism (e.g. SharedPreferences, SQlite etc.) in a class implements that interface. This is where your Android specific stuff will be hidden.
class SharedPrefRepo : SampleRepo
override fun saveData(...)
override fun getData(...)
Ideally you'll want some injection mechanism so you can inject an instance of the above to your model class (e.g. Dagger). It requires some more plumbing code, but that is the price of loose coupling. For a simpler app, like what you're doing, all of this is overkill. But if you're trying to study proper Android app architecture and loose coupling then it's worth exploring how to do it properly.
Thank you Eugene for your answer, I find it a very good solution. I still have some questions: 1. Every call toSampleRepo
call will be performed inCircularModel
model (the Model implementation), right? 2. When should we callsaveData
? At everygetModelNextState()
? Or only when we exit from the app?
– justHelloWorld
Mar 7 at 8:06
1) - yes, correct. The Repo class will be inside the Model class. 2) - In this particular case I'd probably save it only when app exits or goes into background. But a real world implementation might want to keep such data constantly in sync so important state changes are persisted as soon as they happen. If your app crashed for example while it's doing something else and you only save when app goes to background then app might get restored with outdated data.
– Eugene
Mar 7 at 8:39
add a comment |
You should use a different persistence mechanism. The onSaveInstanceState() is really used for situations where the OS needs to restore UI state because of things like configuration / orientation changes. It's not a general purpose storage mechanism.
The model is the correct place to persist data and it is correct that you should try to keep the model as Android agnostic as possible. What you can do is define an interface that represents your persistence requirements:
interface SampleRepo
fun saveData(...)
fun getData(...)
Then your preferred persistence mechanism (e.g. SharedPreferences, SQlite etc.) in a class implements that interface. This is where your Android specific stuff will be hidden.
class SharedPrefRepo : SampleRepo
override fun saveData(...)
override fun getData(...)
Ideally you'll want some injection mechanism so you can inject an instance of the above to your model class (e.g. Dagger). It requires some more plumbing code, but that is the price of loose coupling. For a simpler app, like what you're doing, all of this is overkill. But if you're trying to study proper Android app architecture and loose coupling then it's worth exploring how to do it properly.
Thank you Eugene for your answer, I find it a very good solution. I still have some questions: 1. Every call toSampleRepo
call will be performed inCircularModel
model (the Model implementation), right? 2. When should we callsaveData
? At everygetModelNextState()
? Or only when we exit from the app?
– justHelloWorld
Mar 7 at 8:06
1) - yes, correct. The Repo class will be inside the Model class. 2) - In this particular case I'd probably save it only when app exits or goes into background. But a real world implementation might want to keep such data constantly in sync so important state changes are persisted as soon as they happen. If your app crashed for example while it's doing something else and you only save when app goes to background then app might get restored with outdated data.
– Eugene
Mar 7 at 8:39
add a comment |
You should use a different persistence mechanism. The onSaveInstanceState() is really used for situations where the OS needs to restore UI state because of things like configuration / orientation changes. It's not a general purpose storage mechanism.
The model is the correct place to persist data and it is correct that you should try to keep the model as Android agnostic as possible. What you can do is define an interface that represents your persistence requirements:
interface SampleRepo
fun saveData(...)
fun getData(...)
Then your preferred persistence mechanism (e.g. SharedPreferences, SQlite etc.) in a class implements that interface. This is where your Android specific stuff will be hidden.
class SharedPrefRepo : SampleRepo
override fun saveData(...)
override fun getData(...)
Ideally you'll want some injection mechanism so you can inject an instance of the above to your model class (e.g. Dagger). It requires some more plumbing code, but that is the price of loose coupling. For a simpler app, like what you're doing, all of this is overkill. But if you're trying to study proper Android app architecture and loose coupling then it's worth exploring how to do it properly.
You should use a different persistence mechanism. The onSaveInstanceState() is really used for situations where the OS needs to restore UI state because of things like configuration / orientation changes. It's not a general purpose storage mechanism.
The model is the correct place to persist data and it is correct that you should try to keep the model as Android agnostic as possible. What you can do is define an interface that represents your persistence requirements:
interface SampleRepo
fun saveData(...)
fun getData(...)
Then your preferred persistence mechanism (e.g. SharedPreferences, SQlite etc.) in a class implements that interface. This is where your Android specific stuff will be hidden.
class SharedPrefRepo : SampleRepo
override fun saveData(...)
override fun getData(...)
Ideally you'll want some injection mechanism so you can inject an instance of the above to your model class (e.g. Dagger). It requires some more plumbing code, but that is the price of loose coupling. For a simpler app, like what you're doing, all of this is overkill. But if you're trying to study proper Android app architecture and loose coupling then it's worth exploring how to do it properly.
edited Mar 7 at 6:21
answered Mar 7 at 3:41
EugeneEugene
17619
17619
Thank you Eugene for your answer, I find it a very good solution. I still have some questions: 1. Every call toSampleRepo
call will be performed inCircularModel
model (the Model implementation), right? 2. When should we callsaveData
? At everygetModelNextState()
? Or only when we exit from the app?
– justHelloWorld
Mar 7 at 8:06
1) - yes, correct. The Repo class will be inside the Model class. 2) - In this particular case I'd probably save it only when app exits or goes into background. But a real world implementation might want to keep such data constantly in sync so important state changes are persisted as soon as they happen. If your app crashed for example while it's doing something else and you only save when app goes to background then app might get restored with outdated data.
– Eugene
Mar 7 at 8:39
add a comment |
Thank you Eugene for your answer, I find it a very good solution. I still have some questions: 1. Every call toSampleRepo
call will be performed inCircularModel
model (the Model implementation), right? 2. When should we callsaveData
? At everygetModelNextState()
? Or only when we exit from the app?
– justHelloWorld
Mar 7 at 8:06
1) - yes, correct. The Repo class will be inside the Model class. 2) - In this particular case I'd probably save it only when app exits or goes into background. But a real world implementation might want to keep such data constantly in sync so important state changes are persisted as soon as they happen. If your app crashed for example while it's doing something else and you only save when app goes to background then app might get restored with outdated data.
– Eugene
Mar 7 at 8:39
Thank you Eugene for your answer, I find it a very good solution. I still have some questions: 1. Every call to
SampleRepo
call will be performed in CircularModel
model (the Model implementation), right? 2. When should we call saveData
? At every getModelNextState()
? Or only when we exit from the app?– justHelloWorld
Mar 7 at 8:06
Thank you Eugene for your answer, I find it a very good solution. I still have some questions: 1. Every call to
SampleRepo
call will be performed in CircularModel
model (the Model implementation), right? 2. When should we call saveData
? At every getModelNextState()
? Or only when we exit from the app?– justHelloWorld
Mar 7 at 8:06
1) - yes, correct. The Repo class will be inside the Model class. 2) - In this particular case I'd probably save it only when app exits or goes into background. But a real world implementation might want to keep such data constantly in sync so important state changes are persisted as soon as they happen. If your app crashed for example while it's doing something else and you only save when app goes to background then app might get restored with outdated data.
– Eugene
Mar 7 at 8:39
1) - yes, correct. The Repo class will be inside the Model class. 2) - In this particular case I'd probably save it only when app exits or goes into background. But a real world implementation might want to keep such data constantly in sync so important state changes are persisted as soon as they happen. If your app crashed for example while it's doing something else and you only save when app goes to background then app might get restored with outdated data.
– Eugene
Mar 7 at 8:39
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55034496%2fhow-to-restore-model-state-in-mvp%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown