keep ViewModel data on re-creation - android

Currently i want to create an app with some sort of registration and payment flow.
I use the MaterialStepper library to have one Activity with Fragments each representing one step in the flow.
The Activity has a Android Architecture Component ViewModel and the ViewModel contains several properties for the Fragment. I use LiveData and two-way Databinding for my input fields.
Some data is reused in several Fragments thats why i used only one ViewModel for several fragments.
When the application is in foreground it works like expected, Fragments get re-created and the fields keep their values.
My problem is now when I pause the activity and resume it later. The ViewModel itself can get recreated as well and therefore looses its data.
What is a good approach to avoid the loss of data in that situation?
I read in an article that you should store some values in onSaveInstanceState (e.g. a searchquery to recreate the ViewModel). But isn't that way to much in my situation for ~30 input fields?)
Is a Room database a good approach to insert/update values in the database when the user edits the input fields and observe that LiveData objects instead? (unfortunately i have no experience with Room yet)
I would be glad about any help or examples (:

Related

Android Realm asynchronous architecture in app with Activities & Fragments

I've been using Realm with UI thread writes until I found out the UI was unusable at some point with significant database volume.
I'm now trying to figure out how to properly orchestrate asynchronous writes in app with activities and fragments showing data list and screens to enter the data.
At this moment, my problem is:
I have an Activity A, with its own Realm instance, listing data and listening to realm changes to update itself.
If I want to add more data, I create an Activity B with its own Realm instance.
I've started listening to the onSuccess callback of the transaction to refresh() the Realm instance in order to trigger Realm listeners and have Activity A update itself. Unfortunately it doesn't work when I quickly go back to activity A because the Realm of Activity B is closed and onSuccess is not getting called.
At this point I'm not sure how should I organize all this. I see the option where I don't create Activity B and use fragments but having to do this everywhere in my app doesn't feel great and might be error prone.
What's the best practice for this use case?
Thanks a lot!

LiveData Vs StateFlow: Should we switch from Live data to State Flow?

I have come across articles that recommend switching to StateFlow.
Like the one here.
Also in the new Android studio, StateFlow support is automatically included in the functionality of data binding, including the coroutines dependencies.
Live data is already in use in most of the apps.
Should we migrate from LiveData to StateFlow? What are the benefits?
There is not much difference between State Flow and Live Data. The Main difference come in that State Flow requires an Initial value hence no need to check for nullability. The Second Difference come in unregistering the consumer; Live Data does this automatically when the view goes to STOPPED state while State Flow does not. To achieve similar behaviour as Live Data, you can collect the flow in a Lifecycle.repeatOnLifecycle block.
Benefits of State Flow
State flow is included in coroutines library and can be used in Multiplatform Projects
Using one API in your project(Flow), not two (LiveData and Flow).
It's Kotlin, Why Not
It depends on what you want,
If you want a manual, full and versatile control over the app , go for state flow
If you want a partially automatic or relatively easy-to-use method for your app , I will say - stick with live data
In case If you want to know my personal opinion, it's state flow, as i prefer control over easy-to-use. I don't mind writing a few extra lines for it as it can be useful for me sometimes.
Think of it like using a soda opener for soda and using a nail cutter
I can do it with both but the soda opener Is easy to use in this case but , don't have much versatility like nail cutter.
And at the end of the day , I use state flow everytime because, I am lazy to learn live data for some projects as state flow can do what live data can even though live data will be much easier.
And you should decide what you want to choose and if you're not as lazy as me , I recommend go with both and use the one which is suitable each time.
Cheers.
Flow is the best practice
Livedata is used to observe data without having any hazel to handle lifecycle problems. Whereas Kotlin flow is used for continuous data integration and it also simplified the asynchronous programming.
Take Room Library as an example. First, it used livedata to transmit data from the database to UI. It solved most of the existing problems. But when there are any future changes in the database livedata is helpless in this situation.
After a while, the room used Kotlin flow to solve this problem. With Flow as return-type, room created a new possibility of seamless data integration across the app between database and UI without writing any extra code
read this article on medium website
In Android, LiveData and State are two classes that can be used to hold and observe data in your app. Both classes are part of the Android Architecture Components library, which is a set of libraries for building robust, testable, and maintainable apps.
LiveData is a data holder that is lifecycle-aware, meaning it only delivers updates to observers that are in an active state. It is useful for holding data that needs to be observed and updated in the UI, such as data from a network request or a database query.
State is a data holder that represents an immutable state value that can be observed. It is useful for holding data that does not change often, or data that should not be modified directly.
Which of these classes is "best" to use depends on your specific needs and requirements. Here are a few factors to consider when deciding between LiveData and State:
Mutability: LiveData is mutable, meaning its value can be changed, while State is immutable, meaning its value cannot be changed directly.
Lifecycle awareness: LiveData is lifecycle-aware, while State is not.
Transformation: LiveData supports transformation through the use of the Transformations class, while State does not.
In general, if you need to hold and observe data that needs to be updated in the UI and you want the data to be lifecycle-aware, LiveData is a good choice. If you need to hold and observe data that is immutable or does not change often, State is a good choice.
It is also worth considering whether you need to transform or map the data being held and observed. If you do, LiveData is a better choice because it supports transformation through the Transformations class.

In MVVM, is the ViewModel always necessary?

I'm new to making android apps, Kotlin, and just trying to get my head around the MVVM design pattern.
I'm attempting to make a login screen while also integrating well with my team's existing code. Making the login screen work went well until I noticed that I was running into life-cycle issues with uninitialized lateinit vars (even though the code definitely ran the initialization statements) like SharedPreferences or the username and password fields etc.
After reading up more on MVVM, I believe that the existing code which I was learning from (which contains lateinit vars for Context, the Fragment, and View within the ViewModel etc) is fundamentally flawed and fails to decouple the ViewModel from the View life-cycle.
However this has me confused. To my understanding, the ViewModel is supposed to contain the business logic and any data which we want to survive configuration changes. On the other hand, the LoginFragment should only contain UI and OS interactions such as displaying the View or capturing input.
The LoginViewModel only contains code interfacing between the elements of fragment_login.xml and SharedPreferences, or logging errors:
resetFields(): empties the fields to blank
onLoginButtonClicked(): just calls the Retrofit function to POST the username/password a server for authentication
onLoginSuccessful(): saves the data to SharedPreferences
onLoginUnsuccessful(): changes the field's error message and logs the error
Because I used DataBinding on the xml elements, nothing (as far as I can tell) needs to be independent of the life-cycle (or rather, several things require access to the context or fragment!).
What is the proper way to go about this? Currently I am thinking that the ViewModel simply shouldn't exist and that all functionality (of which there is very little) should actually just be within LoginFragment). I was considering learning about and using LiveData next, but I just can't see how LiveData or ViewModel are necessary in this situation.
The main goal of any architectural pattern is to achieve Decoupling, Single responsibility and restricting Anti Patterns, to be precise code should be more readable, scalable and easily testable.
I know in some instances using this patterns might seem redundant for your use case, but always keep scaling in mind when ever developing even a simple feature. This will pay off in long term and help peers understand and isolate code better.
In Android, always remember view or UI(Activity/Fragment) should be as dumb as possible, only responsibility of them should be to listen to user touches and display data, by doing so you can test all your logic in isolation without relying on Android Framework.
MVVM is once such pattern designed keeping pain points of Android in mind, it does not cause any harm using it when needed to delegate even simple tasks like storing data to preferences, minor transformations to data before displaying. Let's say you have a static page which just displays static data using String and nothing else then you can avoid ViewModels.
MVVM pattern does not enforce you to use ViewModel for every Fragment/Activity, it recommends using it when needed as a best practice, ViewModel is just a data holder which persists configuration changes.

Are there any concerns using an object to store data retrieved from a server?

Will the Object be around for as long as the app is in the background? Does anyone know when a Kotlin Object get removed from memory and reset in Android? Should I just use a ViewModel instead?
When the app is in the background, you can't know what the system will do with it so you can't store in memory data you want to persist.
You have different solutions:
If it's data from a server, you can make the call again if the app has been destroyed between the moment the user put it in the background and the app is brought back.
You can store the data locally.
In the second case you have 3 solutions:
Persist the data into a SQL database, using a solution like Room for instance. This is usually the way to do it.
Persist the data into the Shared Preferences. Used for light data, like settings or small preferences
Store them into a file (usually not a good approach)
A ViewModel is not a way to persist data. It will only persist data in memory. It is good to keep the data when the UI has been destroyed (app changes orientation, or Fragment put in the backstack for instance)
But if the app is killed (for any reason), so will be the ViewModel and everything it contains.
However following a MVP or MVVM (using ViewModel) pattern is a good way to build you app as it decouples the UI from the logic and helps with tests.

Synchronizing data between active activities / fragments

I have to solve a theoretical problem and just want to get feedback about the best pattern / practice to solve this in android.
Task:
An app could have several activities / fragments showing a list of objects. If one object is present in more than one list at the same time, I want to synchronize changes to this object. So e.g. if I delete the object it should disappear in all lists.
The restricts are that
I don't know which lists are currently instantiated
Every list has it's own object instance. Data is not shared directly between lists
My solution so far would be to
define a Storage class which provides methods for data access
create a custom Application class and instantiate the Storage class with the application context (which is needed for e.g. content provider access)
the Storage class defines a Listener where each activity can register itself
if an activity modifies an object, which it has to do through the (Application) Storage, the Storage class sends an event to each activity / fragment registered so they can adopt the changes.
Does anyone know a better solution for that? And is my solution conform with the android lifecycle?
Thanks a lot for every kind of useful feedback
If you want to deal in Object then read up on implementing Services and Binding to them. You can provide all your objects with your own API methods and return values. If your data fits into a data cursor model, then you should read up on building your own ContentProvider. It has data observation built in and all the Adapters support it already.
Your solution seems pretty good. You could use an EventBus like Otto http://square.github.io/otto/ to send an event to all your activities/fragment when an object is modified.
If you insist on maintaining the separate lists in separate Activity/Fragment instances, then you will be prone to lifecycle problems (you might miss an object modification event while you're paused or something). Otto or other EventBus libraries might help.
However, I think it would be much simpler to host all those lists (and their possibly-shared objects) in a local bindable Service. Each Activity/Fragment can then simply bind/unbind to it in onCreate/onDestroy, thus guaranteeing an up-to-date view of those lists.
See http://developer.android.com/guide/components/bound-services.html
Another similar solution would be to host all those lists in a retained Fragment. Using retained Fragments would be simpler than a Service because you don't have to write all the bind/unbind code. However, retained Fragments might not work as well as a Service if you have multiple Activity components that need access to the same lists of objects.
Yet another hacky solution is to just host all those things in the Application instance itself (effectively a global variable). Then your Activity/Fragment code can just call ((MyApplication) getApplication()).getFooList() to get to those objects.

Categories

Resources