简体   繁体   中英

Handle data in ViewModel and Fragment in MVVM

I've seen quite a lot of tutorials but didn't really managed to get myself to properly understand how to handle some cases in MVVM.

Let's say that there is a repository that fetches data from a DAO which uses Room

class Repository(){

  fun getItems() = itemsDAO.getItems()

}

A ViewModel that queries the Repository

class FragmentViewModel:ViewModel(){

    val items = repository.getItems()

    fun updateItem(Item item){
       repository.updateImte(itemm)
    }
}

And a fragment

class MyFragment:Fragment(){

   //onViewCreated
   viewModel.items.observe(...){
        //if result, update the views
     }

  buttonUpdateItem.setOnClickListener{
    viewModel.updateItem(Item item)    
  }

}

This is the approach I understood from tutorials. Basically I have some things to clarify and I would like to ask for your help.

a. Given this implementation of the ViewModel if the user rotates the device and the fragment gets recreated, doesn't this mean that the database will be queried again when observe will be added? I am thinking of an updated version of ViewModel like

  class FragmentViewModel:ViewModel(){
        private final var itemsObservable;


       init {
           itemsObservable = repository.getItems()
        }

       fun items(){
           return itemsObservable
       }

        fun updateItem(Item item){
           repository.updateImte(item)
        }
    }

If I am right, this should allow to return the initial values from db and not call again the db in case of fragment recreation.

b. How should the ViewModel act on the Fragment interraction, more precise on button click event? Should the fragment as in the sample above, call the viewModel.updateItem function or the viewModel should return a onClickListener variable which should be set to the button?

c. should the arguments passed to the fragment also be added to the ViewModel ?

d. As you can see, the ViewModel holds variable for LiveData<List<>> so for instance, if I want to update an item, then the fragment passes that Item . Is this a good approach?

First I would like to point you to Android Architecture Blueprints on GitHub:

The focus of this project is on demonstrating how to structure your code, design your architecture, and the eventual impact of adopting these patterns on testing and maintaining your app. You can use the techniques demonstrated here in many different ways to build apps. Your own particular priorities will impact how you implement the concepts in these projects, so you should not consider these samples to be canonical examples.

These are the official examples of different architectures in Android, you should definitely check that out as an inspiration for you own projects.

a. Your updated version is the correct way to do this - to retrieve a list of items, invoke the repository method once and store the return value in the ViewModel . Use LiveData<List<Item>> as a return value in your DAO and Room will automatically notify your Observer in the Fragment of any changes.

b. ViewModel can have the updateItem(item: Item) method. The onClickListener should be placed in the Fragment . You might want to do some validation in the Fragment as well before invoking the updateItem method. Also it is important to not hold any View references in the ViewModel .
To notify the Fragment about the update status, you might consider having another LiveData field in the ViewModel (for example errorMessage: LiveData<Int> ) and assign it the R. id of the string resource you would like to display. This way you move the logic of determining the specific message to display from the Fragment to the ViewModel .

c. You only need some arguments in the ViewModel . For instance, when you have an id extra argument passed to the Fragment in a Bundle , you would init the ViewModel with this id to load the item.

d. Passing the Item can definitely be a good approach. You can also consider creating a Presenter to separate some logic out of the Fragment (so it does not work with the Item ). You will find more information and examples on the GitHub link above.

So I think there are different approaches to choose from depending on the app you are developing. Testing is very important and after implementing one approach you will find how it affects the ease of writing your tests. But this is how I see the answers for your questions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM