Android MVVM design - should i split my viewmodel class in two? - android

I have an app with 2 distinctly seperate modes, (setup and run timers).
The app allows multi factor inputs from a user on one fragment and once the user wants the timer started, the app switches to a running fragment to show information about their running timer and it's setup.
I've designed an MVVM architecture for this, with my own class that extends ViewModel, my shared viewmodel has two distinctly different types of logic, setup logic (to check, parse and revise inappropriate user inputs), and running timer logic (to manage all the logic, data and state for a running timer from a user's inputs).
My shared viewmodel class is not small as the process of checking all permutations of user input is complex.  I'm wondering is it a bad idea to put all this logic into one viewmodel class? The setup portion is designed to be simple and all setup state is saved (so 10-20 seconds for the user to setup a timer seems appropriate), whereas the timer is designed to be allowed to run for hours, largely with the screen off.
 
Should I split the viewmodel logic into two different viewmodel classes to make a running timer more memory efficient?
I see a clear seperation of concerns and once I have my Room database designed and programmed, only the running timer will save data to the database. I want to keep the fragment classes as lightweight as possible.  If this is a sensible design choice, ill need to be careful with memory leaks between the two states, otherwise im defeating the purpose.
Edited to differentiate between the ViewModel object and a Shared viewmodel idea

As a_local_nobody says, it's up to you to decide how to design your app and distribute the responsibilities.
In case you are looking for our opinion about your philosophical doubts, I have to say that although the concept of the Shared ViewModels is very widespread, I am not a big fan.
In my projects, the most common and logical thing is that each ViewModel manages the logic of a single view. I always treat Shared ViewModels as an exception to the rule, since abusing them usually leads to a very tightly coupled code, very difficult to test and with unexpected side effects.

Related

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.

Implement Redux with Android Observer/Livedata/Coroutine/Kotlin

Consider the Android app architecture that is recommended by Google: https://developer.android.com/jetpack/docs/guide
This architecture is based on ViewModels and Observables, therefore I would categorize it as "Model-View-ViewModel" (MVVM) architecture.
This is quite different to React-Redux. Whereas the Android architecture encourages bi-directional dataflows between Views and ViewModels, Redux enforces a uni-directional dataflow in a circle.
Moreover, the Android architecture keeps state in several ViewModels, whereas Redux enforces a centralized store.
Now my question is how to implement Redux with native Android libraries.
My first attempt would be:
Implement a centralized store as a Kotlin Singleton object.
The store provides a sendAction-method that takes an action, puts it in a queue and then returns quickly.
Actions are pure Kotlin data classes because they should not contain any logic.
Within the store, implement a Kotlin-Coroutine that picks up actions from the queue and dispatches them with a huge switch-statement.
Use a Room-database + some ephemeral state as a model. In particular, the ephemeral state controls which Fragment/Dialog is shown at any given time.
Ensure that the state is only mutated by the Coroutine.
Use observable livedata (androidx.lifecycle.LiveData) to re-render the UI whenever the Room-database or the ephemeral state changes.
Since observables are not enough to control an Android UI, I would also need a function that compares the current fragment/activity with the expected state, and e.g. trigger a FragmentManager transaction if a deviation is detected.
However, a few points are not clear:
How to keep activity/fragments in sync with the global state? Perhaps I would use a single activity and replace fragments as needed, depending on the current state of the store.
How can I implement both async + sequential action dispatching? Perhaps I would implement a single Kotlin-Coroutine that picks up incoming actions from the queue and dispatches them straight on the UI thread.
How can we ensure that the entire UI is re-rendered before new actions are dispatched? Perhaps I would stall the dispatching coroutine until there are no more other runnables in the queue of the UI thread?
You are right to say there are some limitations with MVVM.
Redux-style architecture tends to get called 'MVI' or 'Unidirectional' in Android.
There are some attempts at implementing this architecture in Android already that you can take a look at to help answer your questions:
MvRx
Mosby
In addition, this summary page
has a list of articles/libraries describing the approach.

Clean architecture. What are the jobs of presenter?

I have been reading some articles about the clean architecture, and how it can be implemented in android. I saw the sample app which shows its Android Implementation. Also, I went through a nice talk on Clean architecture on Android
So, I kind of understand most of the concepts, but there is some clarity that I would like to get on certain things.
As per my Understanding,
The View layer is the outer layer which deals with the UI, and
framework related stuff
The presenter is the direct communicator for the view, which accepts user inputs, and executes certain use cases based on this by passing it to the use case layer or the interactor layer.
Interactor executes the use-case, give it back to the callback sent by presenter,
Presenter again converts this result into a view understandable data structure (a ViewModel) and just pass it back to the view.
I am not listing more details about the inner layers like repository since my question is related to the above-mentioned steps
Here, does the presenter have the only job of acting as a mediator between UseCases and UI, as a data dispatcher?
Does it only do the view model to use case model conversion and vice-versa?
The input validation logics rely on which layer? Can it be inside the presenter? For example, if we take a small use case of a sign-up process,
Once the user entered the details and clicked sign-up button, and data sent to the presenter, is it like
Presenter validates the input values if any error is there notify
the view
If values are proper, convert it to a use case model, and execute
certain use case, and once the result is given by the interactor,
again convert to view model, send it to view.
And the second question is, who controls the navigation? The View or the Presenter or the UseCase?
who decides where to go next?
For example - Consider a use case of a login process, Where user will enter the credentials and click OK.
On successful login,
If users e-mail is not verified, go to email verify screen
If users profile is not completed, set-up the profile then only go to home screen
If user is new, show new offers screen, else directly go to home screen
So, who is responsible for making these decisions on which screen to go next? Is it the presenter, which decides and navigate the view accordingly? Or is it the use case handlers responsibility to inform the presenter what is the next State?
Sorry for making the question too long, but I just wanted to elaborate my current understandings. Thanks in advance
Here, does the presenter have the only job of acting as a mediator
between UseCases and UI, as a data dispatcher?
Yes
The input validation logics rely on which layer? Can it be inside the
presenter?
validation should rely on business layer not the presentation, can it be inside the presenter? sure it could, but what if you have multiple screens that take similar inputs, do you have to repeat your validation logic inside each presenter! you can argue that you can make a base presenter, but it's not the perfect solution, because presenter should have one purpose.
And the second question is, who controls the navigation? The View or
the Presenter or the UseCase?
do you consider the navigation is part of the Domain or the presentation or the data layer, it's likely related to the presentation layer, but you could make a small component inside the presentation layer which is control the whole navigation generically, So you can use this component the moment you decide that you do need other platform and throw your activities away. you can find this approach in the sample you've mentioned.
EDIT:0
How you pass data between modules where they have different models?
you simply use mappers, and the reason is to make each module has its own models or entities, so it would be easy to test each module separately.
About presenter and view, let's say you want show error message, presenter decides why it would be shown, view decides how it would be shown.
I think the problem in understanding the clean code presentation layer with Android, that Activities and fragments aren't only view, they're also The process and the lifecycle which your code would be live in, clean code came along to separate spaghetti code on those Activities and fragments.
EDIT:1
adding to the last point, it's clear now that Google and the support team there made a great effort to make Activities and Fragments dummy views as possible via introducing the great set of libraries "Architecture components". I encourage anyone to check them out, even if you're using MVP, you'll find a great benefits.

Can I use the Application class as the Model for MVC in Android

Sorry. I'm new, so I'm experienced, but to follow the MVC design pattern in Android, where is the model stored? I was thinking in Application since it pretty much has a very wide scope and any component can pull from it. Is this a good way of thinking?
On a project that we have here, we do use the Application to persist it but in a certain structured pattern.
Just to start with, the Model is, as you would guess, layered through classes that will represent your persistent entities, so e.g. if you persist clients, you will have a Client class that will hold it's structure, so I guess when you say about Model, I think you talk about the persistence of state-full model objects that will live across your application lifecycle.
We use android annotations just to start with. We use singleton classes (Annotated with #EBean(scope=Scope.singleton)) and our Application object has a reference to that singleton.
We have other entities (singletons as well) that we use as controllers that are the only ones that are able to access and manipulate at certain degrees with that "model singleton" and our activities have an interface-like communication with the controllers, those controllers can access the persistent data on the "model singleton" and provide feedback to the activities through it's interface.
In general, it's probably better to use a ContentProvider or even a singleton class. The problem with keeping state in your Application is that if any part of your app ever needs to run in a different process, that process will have its own copy of the Application. Running things in separate processes isn't common, but there are a few reasons to do it. A singleton class doesn't address the problem of sharing state with another process, but the other process might not care about the application's model. If the model is in the Application, the other process gets a copy whether it wants it or not.

Android pass persistent information in bundles or use singleton pattern?

Just wondering what is a better practice to pass information between activites, adding it to a bundle or using a singleton class to store and access this data. I have used both in the past for various android side projects, but I am now working on an android project that is of much larger scale, so would prefer to do things right towards the beginning.
My application authenticates users and then will have to do various queries based on it's id. To minimize coupling between activities, I would think just adding the id to the bundle, and then letting each activity query for the information that it needs, would be the best bet; however to increase responsiveness, I was leaning towards using a singleton class to store persistent information, preventing more queries than need be.
Personally, I would create an extension of Application to store the state of your app and share data between the different activities. The Application acts as the context for your whole app and Android guarantees there will always only be one instance across your app. Hence it works similar to defining your own Singleton, but using Application will allow Android to take control of the life cycle of your shared data and basically do the memory management for you.
Here are some more details. If you go down this path, you can simply add any getter/setter (or other) method to your application extension to store/retrieve data and do operations on it. Especially the latter can become quite a pain to manage (and keep consistent) when using Bundles passed back and forth between activities. If would only use a Bundle if the data is needed in just one or two places that are neighbours in the activity flow and does not need any (complex) operations to be run on it.
The better way to go for you is to use SharedPreferences to keep userId you need to keep and reuse. Of course you can use singleton approach or even Application class, but the data will be lost after application is killed.
The only time I pass data between Activities via bunlde is if it's something that I won't need to access for a while(i.e the the resID of a resource I want to use only once in the calling activity, etc). I would also think the difference in responsiveness would be very minimal, so that shouldn't be of concern. I suggest the singleton approach
Passing bundles is a tedious job. You'll have to pass a bundle for every change in activity to make sure that the value is not lost, even if you're not using the value in the called activity.
Singleton pattern have some bad results. For example:From Main activity you call secondary activity. Phone call interrupted your work.After ending phone call Android is trying to bring secondary activity to screen. Here is my nightmare - many users complaint about exceptions - Google reported to me NULL pointers in my singleton. So you have to provide not only singleton, but all data inside singleton have to be as singleton too. This maked come very complicated :(

Categories

Resources