androidviewmodelmutablelivedataviewmodelproviders

Dynamic parameters in viewmodel Android


How can I reuse the parameter of a ViewModel in Android? I have a recycle viewer filled with data from a database based on a parameter: selectedDate. How can I reuse it in a fragment, in this way to refresh the recycle viewer? So far I'm using a ViewModelFactory:

public class MyViewModelFactory implements ViewModelProvider.Factory {

    private Application mApplication;
    private String mParam;


    public ShiftViewModelFactory(Application mApplication, String param) {
        mApplication=mApplication;
        mParam = param;
    }


    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        return (T) new MyViewModel(mParam);
    }
}

And I'm loading it in an onCreateView:

myViewModel = ViewModelProviders.of(this, new myViewModelFactory(selectedDate)).get(MyViewModel.class);

How can I change the parameter selectedDate and then refresh the data?

Here is my ViewModel

public class ShiftsViewModel extends ViewModel implements IShiftMapCallbackListener {

private MutableLiveData<List<ShiftModel>> coworkerList;
private MutableLiveData<String> messageError;
private IShiftMapCallbackListener coworkerInfoCallbackListener;


public ShiftsViewModel() {

    coworkerInfoCallbackListener = this;
}

private void loadCoworkerList() {
    final List<ShiftModel> tempList = new ArrayList<>();
    DatabaseReference coworkerRef = FirebaseDatabase.getInstance()
            .getReference(Common.MAP)
            .child(Common.DATA)
            .child(selectedDate);

    coworkerRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            for (DataSnapshot itemSnapshot : dataSnapshot.getChildren())
                if (!itemSnapshot.child("Operator").getValue().equals("")) {
                    ShiftModel model = itemSnapshot.getValue(ShiftModel.class);
                    tempList.add(model);
                }
            coworkerInfoCallbackListener.onCoworkerInfoLoadSuccess(tempList);
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
            coworkerInfoCallbackListener.onCoworkerInfoLoadFailed(databaseError.getMessage());
        }
    });
}

public MutableLiveData<List<ShiftModel>> getCoworkerList() {
    if (coworkerList == null){
        coworkerList = new MutableLiveData<>();
        messageError = new MutableLiveData<>();

        loadCoworkerList();
    }
    return coworkerList;
}

public MutableLiveData<String> getMessageError() {
    return messageError;
}

@Override
public void onCoworkerInfoLoadSuccess(List<ShiftModel> shiftModels) {
    coworkerList.setValue(shiftModels);
}

@Override
public void onCoworkerInfoLoadFailed(String message) {
    messageError.setValue(message);
}
}

The parameter I want to change is selectedDate:

DatabaseReference coworkerRef = FirebaseDatabase.getInstance()
            .getReference(Common.MAP)
            .child(Common.DATA)
            .child(selectedDate);

Then in the fragment I call it like this:

shiftsViewModel.getCoworkerList().observe(this, shiftModel -> {

        shiftMapAdapter = new ShiftMapAdapter(ShiftsFragment.this.getContext(), shiftModel, operatorShow);

        coworker_recycler.setAdapter(shiftMapAdapter);
        coworker_recycler.setLayoutAnimation(layoutAnimationController);
    });

So how can I change the date let say from "2019-11-14" to "2019-11-15"


Solution

  • You may want to shift from using factory parameter to using what essentially is view model data filter. You'll have to:

    1. Define your "filter": private final MutableLiveData<String> filter = new MutableLiveData<>();
    2. Init your "filter" with some value once model is created (probably with value you are already currently passing into factory: filterText.setValue(...)
    3. Define your view model's live data via transformation (input is what holds your filter):
    Transformations.switchMap(
        filter, (Function<String, LiveData<...>) input -> {
    ...
    }
    
    1. Define some way of changing your filter - every such change will get you fresh data observation:
    void setFilter(String filter) {
        this.filter.setValue(filter);
    }