I am working on an android application which has a recycler view with multiple view types. It was originally a MVP based app, which I am trying to convert to MVVM based architecture with LiveData and ViewModels. I have a home screen with a list of different types of views inside a recycler view. Every view has its own ViewModel and corresponding Model, resulting it with a home screen having recycler view as a collection of different view models.
This is my first implementation of LiveData, so facing some issues with design. I see some options here -
I create a parent HomeViewModel for my home activity which holds a LiveData object, consisting a list of different child ViewModels (representing different view types), making activity to its life cycle owner. Then I update each view(elements of recycler view) from one observer to that LiveData object.
I create individual LiveData objects for every child view/view models and make home activity as life cycle owner for each model/live data and update their views independently from activity with respective observers.
I create individual LiveData objects for every child view/view models and make respective view holder classes as their lifecycle owners and update individual views in respective holder classes.
Please help me suggesting the better way to deal with this or if there is any other approach other than the specified ones.
Thanks
I agreed to create a parent viewmodel such as "HomeViewModel", but I think the creation of viewmodel for each view type seems a little over-engineering, because every time you need to create a new view type, you need to create a new ViewModel, and I dont see any requirement for the view in recyclerview to have a dedicated viewmodel. In my perspective, the best approach is only have 1 viewmodel. Then I suggest you to implement adapter factory pattern for your recyclerview like in this article https://proandroiddev.com/writing-better-adapters-1b09758407d2 . If you have adapter factory pattern like that, you can generalize your recyclerview data, for example you can call it "Visitable" like the post above. Then, your viewmodel can hold just 1 livedata of visitable list, which observed by the fragment/activity.
Related
When working with Bottom Sheets and Dialog how to perform operation:
Use a SharedViewModel with fragment that created this bottom sheet?
Don't use a ViewModel at all?
Creating a separate ViewModel for the BottomSheet?
Any other approach that is best practice
If the bottom sheet/dialog is tightly bound to your "host" fragment (it shares some specific live data), and it is never going to be created from some other fragment, then it's OK to use a shared view model.
If the dialog is dead simple (like one input + 2 buttons), then the viewmodel might not be needed
If the dialog really needs a viewmodel (i.e. it fetches and displays some dynamic data), then a separate viewmodel makes sense
I'll go with the first approach by using a ShareViewModel, but if you understand the underlying layer, shared ViewModel is also ViewModel it's just a name convention we gave it to them.
Also sometimes it becomes tedious to write separate ViewModel to deal with fragments and bottom sheet where a MainActivity ViewModel can also do the exact same thing.
What I meant, in order to avoid complexity I use one view model per activity. Now, whenever I want to execute something in fragment or bottom sheet I just pass the view model in the constructor itself. Many people will think this is bad practice but it's not coz as per the concept of view model it will only be created and destroyed in accordance with the activity's lifecycle and only one instance will be created all along. Also by doing this, I can use Dependency injection with the fragment (I don't think that DI works with navigation component but I think you got my point).
I am just thinking about MVVM when it comes to bottom navigation view.
In this case it is one activity which has multiple fragments. If I use the ViewModel then the view model will hold the data for all fragments, right? Wouldn't this cause memory leaks or be bad for performance?
If I don't use the view model then I would be only holding one single Fragment data at a time.
Am I missing something?
There are multiple ways to implement this. Keep in mind, ViewModel doesn't have to be used only by Activity, it can be used by a Fragment or even a custom View.
In your case, if you have multiple fragments, you can create a ViewModel for each of them (if they are different off course).
The only thing that will kind of go out of MVVM pattern is the communication between fragment and activity.
If you still want to give the ViewModel the responsibility of telling the activity when to replace/remove/change a fragment, you can define an interface in each model (or a general interface) that will act as a callback, and you can set this callback on your ViewModel in onAttach or wherever fits for you.
Now your fragment, can pass the responsibility of notifying the activity to the ViewModel. I think this is one way of getting close to the MVVM patter in the case of Activity/Fragment communication, without to much trouble.
I'm trying to wrap my head around implementation of shared view transitions between fragments
The challenge is coming from the MVVP restricitons:
Adapter of RecycleView has knowledge of selected element and view attached via callback from View
Adapter is passing information about click to ViewModel stripping out all information about view, as it can't hold it. That's because of rule - no android imports in ViewModel except of *arch
ViewModel sends event to Fragment to open another Fragment
At this point Fragment doesn't know what view to use to start transition in .addSharedElement(..)
How to address this issue?
I was thinking about saving reference to clicked View inside Fragment instance but it looks like a cheating
Any ideas and suggestions are very welcome
I am working on an Android test project composed of 3 main parts, each of which developed following the MVP pattern.
These parts are nested into each other and I would like to know if the strategy I am following is the correct/best one or not
Structure:
Book: ViewPager containing different Pages
Page: Custom LinearLayout containing multiple Items
Item: Custom View (in this example a simple button)
Each part uses a MVP structure (so for example for Book I made BookPresenter, BookView and BookModel, and the same for Page and Item)
As a user case I would like to keep track of how many times the user clicks the button and for each time change the Page background to a random color, and when the user reaches the 10th click tell the BookPresenter to go to the second page.
To do so I set up things so
BookView creates the BookPresenter, which in turns creates each PageView.
Each PageView creates the PagePresenter which in turns creates the ItemView (which ultimately creates the ItemPresenter)
In all this, the BookPresenter has a reference to the PagePresenter, and the PagePresenter has a reference to the ItemPresenter, so when some actions need to take place they can communicate to the child or the parent presenter in the structure
Now the question:
Is this the right way to set up a system with nested MVPs?
Because if I then want to have a PageView but instead of in a Book I need to put it in a Newspaper (other class with some alternative behaviour to Book) I still would need to recreate the whole chain of dependencies with Presenters and all the rest...
How does a “Child-Presenter” communicate with its “Parent-Presenter”? They don't (directly, not via EventBus)
From my point of view such Parent-Child relations are code smells because they introduce a direct coupling between both Parent and Child, which leads to code that is hard to read, hard to maintain, where changing requirement affects a lot of components (hence it’s a virtually impossible task in large systems) and last but not least introduces shared state that is hard to predict and even harder to reproduce and debug.
So far so good, but somehow the information must flow from Presenter A to Presenter B: How does a Presenter communicate with another Presenter? They don’t! What would a Presenter have to tell another Presenter? Event X has happened? Presenters don’t have to talk to each other, they just observe the same Model (or the same part of the business logic to be precise). That’s how they get notified about changes: from the underlying layer.
Whenever an Event X happens (i.e. a user clicked on a button in View 1), the Presenter lets that information sink down to the business logic. Since the other Presenters are observing the same business logic, they get notified by the business logic that something has changed (model has been updated).
Source: http://hannesdorfmann.com/android/mosby3-mvi-4
So let's apply this on your example.
You should have something like a Readable (if you want to make an abstraction over Book implements Readable and NewsPaper implements Readable). With Readable.getPageCount() you get the number of pages for ViewPager. With Readable.getCurrentPage() you get the current Page. Then you need some kind of Observer Pattern to be notified whenever the page is changed. You also need a Listener / Observer pattern when the user clicks on a button in ItemView. Such a click would be an Event X from the graphic above. On click on the button you let the information flow down through Presenter to your business logic which changes the Readable object. This change will then notify observers of this Readable object like PagePresenter that then updates the PageView to set the background color of the page.
So the key is: communicate via Business Logic, instead of some View to View or Presenter to Presenter communication.
Hope that helps.
So I have an a presenter that is already tied to an activity. The book says that one presenter should be tied to one view. But now I am adding a few fragments and lots of custom views. I am considering a fragment to be a view as well. The custom views will contain a little bit of logic in them. Both the fragments and custom views are contained in my activity of course.
My question is, should I re-use the same presenter in the fragment and custom views or should each view get its own presenter? I realize this is all opinion based but I want the best approach for testing and keeping code clean.
If i do have one presenter for all these fews then then interface the presenter uses will have many callback methods in it. Meanwhile if i did the opposite and created one presenter for each view it might be easier to read but how would i test it ?
View (Activity) can have multiple Presenters. In case of having multiple CustomViews for Activity, you can have one giant Presenter or Presenter per each CustomView. It depends on this:
If all CustomViews share same needs, one Presenter for all CustomViews is enough. Still two options for Presenter's scope:
Presenter has ActivityScope. Activity uses Presenter and gets called from Presenter. Then sends commands, data to CustomViews
Presenter has ViewScope. Each CustomView creates and destroys same Presenter
In case of CustomViews not sharing same needs, having one Presenter and ViewInterface, they will contain methods of all CustomViews needs, so each CustomView has to implement all declared methods in ViewInterface, leave some empty.
If CustomViews have different needs and method calls to Presenter, they should have their own Presenter.
If CustomViews have different needs and also some common needs, they share common need in one Presenter, specific needs in their own Presenters. Example for this: ActivityOne has CustomViewOne and CustomViewTwo. Common Presenter for both CustomViews can be FeedPresenter(considering both CustomViews have Feed List). Then CustomViewOne will have CustomPresenter1 and CustomViewTwo will have CustomPresenter2 for their specific needs.
Best practice is to create a basepresenter , then create presenter for each view implementing basepresenter