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.
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);
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With