6

I trying to refactor one of my activity class to implement mvp(using mvp mosby library) . I have a RecyclerView and in this view there is some items that some changes apply to them during the run time. for example I do some I/O operation and change one row.

I think it's better to keep my items in presenter class; what is the best practice for this? keep this in 1)presenter or 2)activity or 3)only keep view related item in adapter and all other item in presenter.

the activity now keep items directly and change item row in activity and then notify adapter. isn't better to move all this line in adapter and notify adapter in the adapter class? for example i want change icon of some row.where and which class is responsible for that? adapter? activity? now I want to implement it like this in adapter:

changeItemIcon(int position, int iconRes){
    mImages.get(position).setICon(iconRes);
    notifyItemChanged(position);
}

I invoke this method on activity and invoke activity method from presenter.

is it good? what is the best practice to do this?

UPDATE

also I find this question ( Best way to update data with a RecyclerView adapter ) that using adapter method for changing items. but what about modify? Need I keep reference to items in my activity?

Community
  • 1
  • 1
Siavash Abdoli
  • 1,723
  • 3
  • 21
  • 37
  • 1
    The adapter's single responsibility is to adapt. You give it a list of data, it knows how to create views from them. It's (IMO) not the right place for a `changeItemIcon` method. That's a change to the underlying data that is being adapted. Where that code belongs depends on what's responsible for that data. Probably in the presenter, which sounds like it's your activity (consider extracting that functionality to it's own class so you can reuse it) – zapl Jun 06 '16 at 08:58
  • @zapl ok got it. my activity is not presenter class i create presenter for it during the refactoring!but my view model and login model are same right now! so you mean change view related items in activity and notify adapter from activity?(of course I call my activity method from presenter) I search in internet and find this code on google github: https://github.com/dmilicic/android-clean-sample-app/blob/7dcc3aa037c754d688acabac0a42a0017b1d8f48/app/src/main/java/com/kodelabs/mycosts/presentation/ui/adapters/CostItemAdapter.java as you can see he notify data only in adapter – Siavash Abdoli Jun 06 '16 at 10:04
  • this adapter is not for view but the developer only notify data from adapter. https://github.com/google/iosched/blob/2531cbdbe27e5795eb78bf47d27e8c1be494aad4/android/src/main/java/com/google/samples/apps/iosched/ui/SimpleSectionedListAdapter.java – Siavash Abdoli Jun 06 '16 at 10:15
  • 1
    The last one is a bit special, it's an adapter around another adapter. Forwards notifications from `baseAdapter`. PS: I would not worry that much about random examples from the internet or whether your code is MVP or not. The library has examples which shows certain patterns to do things. Whether that is MVP or not does not matter as long as you have clean code. And that's simpler when you do it however the library inventor imagined you do. – zapl Jun 06 '16 at 10:39
  • @zapl so finaly what should i do?(clean way) change data in activity? my activity have too many lines! I think activity can't handle all of this! If as you say I keep all this lines in activity I meet a large dirty activity. where implement this changes? PS: my question is not about Library ! you can think other part of my code is clean right now! – Siavash Abdoli Jun 06 '16 at 11:02

3 Answers3

6

for example i want change icon of some row.where and which class is responsible for that? adapter? activity?

I know it sounds a little bit strange, but changing an element is always the responsibility of your "business logic", even just for "icons".

The workflow should be as follows (unidirectional data flow):

  1. View appeares, tells presenter to load a list of items
  2. Presenter loads items form "business logic" and registers himself as an observer / listener / callback (whatever you want to call it)
  3. Presenter receives result and tells the view to display the list of items (through RecyclerView and corresponding adapter).

so far is what you have implemented I guess, now it comes to the point where you want to change an item.

  1. User clicks on an item in your RecyclerView which then should trigger to change the icon of this item. Therefore View should call: presenter.changeItem()
  2. Presenter is just the man in the middle in this case and will invoke the "business logic layer" to tell that the item should be changed to new state (icon has changed).
  3. "Business logic layer" will change the models state (change the items icon) and then will notify its observer / listeners that the model has been changed.
  4. Since Presenter is still observing / listening to the business logic layer (see point 2.) the Presenter will be notified (see point 6.) with a new (updated) list of items containing the updated item which icon has been changed.
  5. Similar to point 3. Presenter will tell the view to display the new (updated) list of items (through RecyclerView and corresponding adapter).

Do you see the unidirectional data flow? That is very important. Immutability FTW.

sockeqwe
  • 14,614
  • 22
  • 78
  • 136
  • Thanks for answer and it really good explanation of MVP for my case. But because of my poor grammar you can't understand my problem clearly.after your answer I certainly know that I have to keep data the real data in presenter. But I really modify only one row and pass this to logic layer and server callback me. Assume like for a tweet. I have to say to my adapter to update heart of one row whit animation. This line appear In which class ?items.get(position).setLiked(true) – Siavash Abdoli Jun 06 '16 at 17:02
  • Assume Items is view related model. Presenter should not know about android adapter items as I know – Siavash Abdoli Jun 06 '16 at 17:04
  • `This line appear In which class ? items.get(position).setLiked(true)` Still in business logic. My explanation shown above is still valid. – sockeqwe Jun 07 '16 at 08:27
  • Ok got it. I change all data in presenter and then set them to adapter and call notifyItemChanged(position) from presenter for that position. is it good? also I change adapter data like this: public void swap(ArrayList datas){ data.clear(); data.addAll(datas); } – Siavash Abdoli Jun 08 '16 at 07:19
4

MVP has two different variants: Passive View and Supervising Controller. Depending on your taste, you can stick to one or mix both of them in your app.

If you choose Passive View, you need to hide Model from View and let Presenter format data then set to the View. In this case, you need to keep Model reference in Presenter. View should only hold view-data (adapter) for its displaying purpose.

If you stick to Supervising Controller, you can allow View to directly bind data from Model and ask Model to perform some simple logic. Presenter should only care complex logic, i.e some operations which need to involve Services. In this case, you can give Model (your items) to View (activity) and let it interact with Model in some simple manner.

PS: Please also check out our new MVP framework: Robo MVP at http://robo-creative.github.io/mvp.

Robo
  • 604
  • 3
  • 7
1

I've never used mosby, but I've just read their docs (good reading btw) and here's my understanding:

A recycler view usually consists of the view (android term) and an adapter. Both are connected inside a fragment or activity. In terms of MVP/mosby this is all view layer. The presenter should only retrieve and pass the to-be-shown data from your service (model layer in mosby, "service layer" or "business logic" in other concepts), which in turn gets it from a DAO or repository (model layer).

The docs say that the presenter only handles the view state, not the actual contents. Your state is "showing list".

Hubert Grzeskowiak
  • 10,887
  • 4
  • 47
  • 61
  • I think your overall point is true but this answer do not cover all of my question. I also want to know about where to change and notify my to-be-shown data; in adapter or activity(both are in view layer) or somewhere else. and I want to consider if there is any difference between android app and other platforms – Siavash Abdoli Jun 06 '16 at 10:20
  • The point where you change data depends on a few points: whether that data is part of your business model or only affects GUI; where it comes from (user input, database etc.) and what android view it is part of. The actual GUI handling is done in your holder class which is used by the recycler. How you pass it data depends on the questions above. – Hubert Grzeskowiak Jun 06 '16 at 12:05
  • data come from presenter(presenter maybe get them from database api,etc) and affects GUI – Siavash Abdoli Jun 06 '16 at 12:21
  • How about registering your holder objects as listeners/observers to the model? Any time the model changes, the corresponding observer, i.e. visible list item, updates itself. Consider this code: https://github.com/hubertgrzeskowiak/Virtu/blob/master/app/src/main/java/de/th_koeln/hgrzesko/virtu/conversationlist/ConversationSummaryViewHolder.java#L81 . I'm passing the model (DTO) to the view holder so it can update its values and it leaves a reference to itself on that model. In other words: It starts observing it. Whenever the model changes, it updates all registered observers. – Hubert Grzeskowiak Jun 06 '16 at 14:04
  • It sounds good if do not cause any problem. I think it's better to Add this to your answer – Siavash Abdoli Jun 06 '16 at 17:11