Reputation: 9083
I have list of items shown with MVP pattern. View is an Activity (a.k.a. ItemsList
). I want to show next Activity (also MVP'ed, a.k.a. ItemDetails
) with details of item clicked in ItemsList
.
Model for ItemsList
is fed with data from Repository. So actually it's RMVP. It looks like this:
|->Model<->Presenter<->View [ItemsList]
Repository<-|
|->Model<->Presenter<->View [ItemDetails]
So Model for ItemsList
already knows exactly what Model item was clicked so I could pass it right away from ItemsList
to ItemDetails
without fetching data from Repository again / mapping from data to Model / making new Model for ItemDetails
etc.
How should I pass data (e.g. which item was clicked) between Activities in MVP?
Solution 1
Pass those data with Intent (similar to what is discussed here) but ... then what to do with that data? You unpack it from Intent in Activity (View) while you should have it on the other side of MVP, i.e. in Model. You pass it from View thru Presenter to Model?
But then Model in ItemDetails
is not created from the "downside of MVP" (from Repository) but from "upperside of MVP" (from Presenter).
Solution 2
Pass only ID of clicked item to ItemDetails
View (similar to what android10/Android-CleanArchitecture proposes in UserDetailsActivity with field private int userId
; this is also what googlecodelabs' NoteDetailPresenter uses)
However there may a problem because I may have two implementations of Repository:
ItemDetails
View (however it seems to be over-engineered), similar to what android10/Android-CleanArchitecture proposes in UserDetailsActivity with field private int userId;
ItemsList
Upvotes: 9
Views: 3764
Reputation: 591
When an item is clicked, you should pass that info up to the presenter who will decide what data needs to be sent to which activity. Then your presenter can package the data and target activity class into an intent and pass it back to the original view. For example, something like navigateToActivity(Intent i). The original view starts the activity with the intent it is given. This allows the originating view to be dumb about what the next screen needs to be (as there may be multiple options). Business logic is the presenter's job.
Then the new view's presenter unpacks the data sent with the intent when the presenter is initialized, as Kishan said. The target view is also dumb in terms of knowing what to do with the data in the intent.
Upvotes: 0
Reputation: 16
In addition, I think there's a third consideration - in MVP, you're Model is modelling the problem domain and should be able to exist regardless of the chosen V and P. If your ItemDetails and ItemList are part of the same problem domain, it's likely that your Model would model them both, and what you're infact looking to do is present the data in two different ways (one as a list, one as detail).
In which case, it may be viable to share a Model, and just have different presentation and viewing layers. In which case, once your detail has been passed back to you Model, it's just a case of attaching a new presenter to present the chosen ItemDetail.
Upvotes: 0
Reputation: 389
Recently, I have also used MVP in my application. I found same issue and pass data from ItemListActivity to ItemDetailActivity using intent. I passed model class which implements Parcelable interface and found no issue, it works fine.
The reason is : In ItemDetailActivity, we have to fetch data from database or from repository in your case which increases one operation in your application.
In ItemlistActivity you will perform only single operation to get all the data. While, if you pass data from ItemListActivity to ItemDetailActivity than, you just have to get data in ItemDetailActivity without any special operation.
I suggest you to go for Solution 1.
Upvotes: 1
Reputation: 15
If you are using view-first navigation, I think you can create your own presenter-layer bundle (or something like that) and send it with intent to the new Activity. Then the new Activity will extract this bundle and pass it to the presenter.
Upvotes: 0
Reputation: 587
In an application I have used both those methods plus a third option. In the third option I use an application level cache and stuff the object there and pass the cache key to the new intent. This is a variation of solution 2 without the repo cache. I know I will only need the item in the cache temporarily; therefore, it is very important to remove the item from the cache to prevent memory leaks. I generally like the second solution as I don't have to make the object parcelable (perhaps being a bit lazy). I did not notice performance differences from any of the methods.
In the end, I settled on Solution 1 when passing view models (I have all my view models parcelable). Solution 2 when using domian models (since they are in the database already, it's just easier to pass a key around). Solution 2 with cache if the domian object is in a transient state (either a new domain object not yet persisted or a domain object where the state might be inconsistant with the database i.e. changes not yet persisted and the activity get suspended for some reason)
Upvotes: 0