Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM Set Recyclerview Adapter With Items In Fragment

I am using MVVM pattern with retrofit and recyclerview for the first time. I have made the network call in my viewmodel class but have no idea how to display the data in recyclerview.

Here's my viewmodel code:

public class HomeSessionsViewModel extends ViewModel {

private static final String TAG = HomeSessionsViewModel.class.getSimpleName();

private Context context;

public String sessionImg;
public String title, programName, batchName, batchPlayersCount;

public HomeSessionsViewModel(Context context) {
    this.context = context;
}

public void fetchSessions(String coachId){
    Log.d(TAG, "Call made");
    Call<SessionDetails> call = RestClient.getRestInstance()
            .getSessionsService()
            .fetchSessions(coachId);

    call.enqueue(new Callback<SessionDetails>() {
        @Override
        public void onResponse(Call<SessionDetails> call, Response<SessionDetails> response) {
            if (response.isSuccessful()){
                SessionDetails details = response.body();
                List<Sessions> sessions = details.getSessions();
                for (int i = 0; i < sessions.size(); i++){
                    Log.d(TAG, "Session Name:\t" + sessions.get(i).session_name);
                    sessionImg = sessions.get(i).sessionImage;
                    title = sessions.get(i).session_name;
                    programName = sessions.get(i).program_name;
                    batchName = sessions.get(i).batch_name;
                    batchPlayersCount = sessions.get(i).participants_count;
        //          addData(sessions);
                }
            }
        }

        @Override
        public void onFailure(Call<SessionDetails> call, Throwable t) {
            Log.d(TAG, "Can't Get Sessions:\n");
            Log.d(TAG, t.getMessage());
        }
    });

}

}

and adapter code:

public class SessionsAdapter extends RecyclerView.Adapter<SessionsViewHolder> {

private final Context context;
private List<HomeSessionsViewModel> itemsList;

public SessionsAdapter(Context context, List<HomeSessionsViewModel> itemsList) {
    this.context = context;
    this.itemsList = itemsList;
}

@Override
public SessionsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    HomeSessionsBinding sessionsBinding = HomeSessionsBinding.inflate(inflater, parent, false);
    return new SessionsViewHolder(sessionsBinding);
}

@Override
public void onBindViewHolder(SessionsViewHolder viewholder, int position) {
    HomeSessionsViewModel viewModel = itemsList.get(position);
    viewholder.bindSessions(viewModel);
}

@Override
public int getItemCount() {
    if (itemsList == null) {
        return 0;
    }
    return itemsList.size();
}

}

and in my fragment I have this:

public class HomeFragment extends Fragment implements OnItemClickedListener, DatePickerListener {

private RecyclerView actionsRV, sessionsRV;
private List<ActionsViewModel> actionsList = new ArrayList<>();
private ActionsAdapter actionsAdapter;

private HomeFragmentBinding fragmentBinding;
private HomeFragmentViewModel homeViewModel;
private HomeSessionsViewModel sessionsViewModel;

private List<HomeSessionsViewModel> sessionsViewModelList = new ArrayList<>();
private SessionsAdapter sessionsAdapter;

@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                         @Nullable Bundle savedInstanceState) {
    fragmentBinding = DataBindingUtil.inflate(inflater, R.layout.home_fragment, container, false);
    homeViewModel = new HomeFragmentViewModel(getActivity());
    fragmentBinding.setHomeViewModel(homeViewModel);
    init();
    return fragmentBinding.getRoot();
}

private void init() {
    addActions();
    initPicker();
    populateSessions();
}

private void initPicker() {
    fragmentBinding.datePicker.setListener(this)
            .setMonthAndYearTextColor(getActivity().getResources().getColor(R.color.white))
            .setDateSelectedColor(getActivity().getResources().getColor(R.color.white))
            .setDateSelectedTextColor(getActivity().getResources().getColor(R.color.event_color_03))
            .setTodayButtonTextColor(getActivity().getResources().getColor(R.color.white))
            .setTodayDateTextColor(getActivity().getResources().getColor(R.color.accent))
            .setUnselectedDayTextColor(getActivity().getResources().getColor(R.color.white))
            .init();
}

private void populateSessions() {
    sessionsViewModel = ViewModelProviders.of(this).get(HomeSessionsViewModel.class);
    sessionsViewModel.fetchSessions("4086");
  //sessionsViewModel.fetchSessions();
  //sessionsViewModel.fetchSessions(""); // TODO: 3/16/2019 Use coach id from db

    sessionsRV = fragmentBinding.sessionsRV;
  //sessionsViewModelList = sessionsViewModel.items();
    sessionsAdapter = new SessionsAdapter(getActivity(), sessionsViewModelList);


}

private void addActions() {
    actionsRV = fragmentBinding.actionsRV;
    actionsRV.setHasFixedSize(true);
    LinearLayoutManager hlm = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
    fragmentBinding.actionsRV.setLayoutManager(hlm);

    ActionsViewModel action1 = new ActionsViewModel();
    action1.name = "Attendance";
    action1.img = getResources().getDrawable(R.drawable.ic_attendance);
    actionsList.add(action1);

    ActionsViewModel action2 = new ActionsViewModel();
    action2.name = "Evaluate";
    action2.img = getResources().getDrawable(R.drawable.ic_evaluate);
    actionsList.add(action2);

    ActionsViewModel action3 = new ActionsViewModel();
    action3.name = "Players";
    action3.img = getResources().getDrawable(R.drawable.ic_players);
    actionsList.add(action3);

    ActionsViewModel action4 = new ActionsViewModel();
    action4.name = "Programs";
    action4.img = getResources().getDrawable(R.drawable.ic_programs);
    actionsList.add(action4);

    ActionsViewModel action5 = new ActionsViewModel();
    action5.name = "Tips/VOD";
    action5.img = getResources().getDrawable(R.drawable.ic_tips_vod);
    actionsList.add(action5);

    actionsAdapter = new ActionsAdapter(getActivity(), actionsList);
    actionsAdapter.setItemClickedListener(this);
    actionsRV.setAdapter(actionsAdapter);

}

@Override
public void itemClicked(int position) {
    switch (position){
        case 0:
            Toast.makeText(getActivity(), "Attendance Clicked", Toast.LENGTH_SHORT).show();
            break;
        case 1:
            Toast.makeText(getActivity(), "Evaluate Clicked", Toast.LENGTH_SHORT).show();
            break;
        case 2:
            Toast.makeText(getActivity(), "Players Clicked", Toast.LENGTH_SHORT).show();
            break;
        case 3:
            Toast.makeText(getActivity(), "Programs Clicked", Toast.LENGTH_SHORT).show();
            break;
        case 4:
            Snackbar.make(getActivity().findViewById(android.R.id.content), "Tips Coming Soon", Snackbar.LENGTH_SHORT).show();
            break;
    }
}

@Override
public void onDateSelected(DateTime dateSelected) {

}
}

Displaying the actions recyclerview was straightforward but I'm not sure how to go about the sessions. I have followed this tutorial series but I'm stuck how to get the data from viewmodel into fragment recyclerview. I have read that adding view widgets into viewmodel can cause memory leaks. Is there any way to do this? Thanks.

like image 405
Darth Plagueris Avatar asked Mar 17 '19 06:03

Darth Plagueris


1 Answers

You can use LiveData for these kind of purposes. LiveData is Lifecycle aware and can be used in ViewModel.

In your ViewModel, add a property of type MutableLiveData.

private MutableLiveData<List<Session>> sessionsLiveData = new MutableLiveData<List<Session>>();

public LiveData<List<Session>> getSessionLiveData(){
    return sessionsLiveData;
}

Set value to this LiveData when network call is made and you have required data for the adapter.

call.enqueue(new Callback<SessionDetails>() {
        @Override
        public void onResponse(Call<SessionDetails> call, Response<SessionDetails> response) {
            if (response.isSuccessful()){
                SessionDetails details = response.body();
                List<Session> sessions = details.getSessions();
                sessionsLiveData.postValue(sessions);
            }
        }

        @Override
        public void onFailure(Call<SessionDetails> call, Throwable t) {
            Log.d(TAG, "Can't Get Sessions:\n");
            Log.d(TAG, t.getMessage());
        }
    });

In your Fragment, observer this LiveData.

viewModel.getSessionLiveData().observe(this, new Observer<List<Session>>() {
            @Override
            public void onChanged(@Nullable final List<Session> sessions) {
                // set Data to adapter here.
                adapter.setData(sessions);
            }
        });
like image 190
Birju Vachhani Avatar answered Sep 26 '22 10:09

Birju Vachhani