What I've Tried: I think this problem lends itself to using MediatorLiveData, however I am unsure how to apply this to my code as the usage I've found online has been mostly for Kotlin. Currently, I am trying to use the MVVM scheme with 2 entities(BPcheck, MEDtaken) with their corresponding Dao and View Models, a repository, a database, and a RecyclerViewAdapter. Initially, I tried to make BPcheck and MEDtaken child classes of Recording, however I ran into issues with Type casting. Next I tried to make each their own separate classes, but then ran into the issue of not understanding to show two LiveData lists in the same recyclerview.
Goal: I am trying to show data from two LiveData Lists within the same RecyclerView, and inflate a different Recyclerview layout dependent on the type of data. In the future I'd like to add a few more LiveData Lists to this Recyclerview, each with their own layouts.
Context: I have been following the following video series to help with app creation: https://www.youtube.com/watch?v=Jwdty9jQN0E&ab_channel=CodinginFlow
My Code:
public class RecordingsRecyclerViewAdapter extends RecyclerView.Adapter{
final int VIEW_TYPE_MEDTAKEN = 0;
final int VIEW_TYPE_BPCHECK = 1;
private List<MedTaken> medTakenList = new ArrayList<>();
private List<BPcheck> bpChecksList = new ArrayList<>();
// !! Ideally, this recordingsList would hold both lists. !!//
private List<Object> recordingsList = new ArrayList<>();
private Context recordings_context;
public RecordingsRecyclerViewAdapter(Context recordings_context) {
this.recordings_context = recordings_context;
}
@Override
// My Attempt at trying to get different datatypes to inflate different layouts
public int getItemViewType(int position) {
if (recordingsList.get(position) instanceof BPcheck){
return 1;
}else{
return 0;
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view;
if (viewType == VIEW_TYPE_BPCHECK) {
view = layoutInflater.inflate(R.layout.recordings_bloodpressurecheck_item, parent, false);
return new ViewHolder_BPCHECK(view);
}
if(viewType==VIEW_TYPE_MEDTAKEN) {
view = layoutInflater.inflate(R.layout.recordings_medtaken_item, parent, false);
return new ViewHolder_MEDTAKEN(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(holder.getItemViewType()==1){
//bind viewholder2
ViewHolder_BPCHECK viewHolder_bpcheck = (ViewHolder_BPCHECK) holder;
viewHolder_bpcheck.systolic.setText(((BPcheck) recordingsList.get(position)).getSystolicBP());
}else{
ViewHolder_MEDTAKEN viewHolder_medtaken = (ViewHolder_MEDTAKEN) holder;
viewHolder_medtaken.subtitle.setText(((MedTaken) recordingsList.get(position)).getMedication().getMedCommonName());
}
}
@Override
public int getItemCount() {
return recordingsList.size();
}
class ViewHolder_MEDTAKEN extends RecyclerView.ViewHolder{
TextView datetime,subtitle;
public ViewHolder_MEDTAKEN(@NonNull View itemView) {
super(itemView);
datetime = itemView.findViewById(R.id.txt_recording_datetime);
subtitle = itemView.findViewById(R.id.txt_recording_subtitle);
}
}
class ViewHolder_BPCHECK extends RecyclerView.ViewHolder{
TextView datetime,systolic,diastolic;
public ViewHolder_BPCHECK(@NonNull View itemView) {
super(itemView);
datetime = itemView.findViewById(R.id.txt_bpCheck_datetime);
systolic = itemView.findViewById(R.id.txt_systolic);
diastolic = itemView.findViewById(R.id.txt_diastolic);
}
}
public class AllRecordingsActivity extends AppCompatActivity {
// !! RecordingViewModel is not created, but I just wanted to give an idea of where I was trying to go with this
private RecordingViewModel recordingViewModel;
private RecyclerView recordingsRecyclerView;
private RecordingsRecyclerViewAdapter recordingsRecyclerViewAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_all_recordings);
recordingsRecyclerView = findViewById(R.id.recordingsRecyclerView);
recordingsRecyclerViewAdapter = new RecordingsRecyclerViewAdapter(this);
recordingsRecyclerView.setAdapter(recordingsRecyclerViewAdapter);
recordingsRecyclerView.setLayoutManager(new GridLayoutManager(this,1));
// !! not really sure what to do here
recordingViewModel = new ViewModelProvider(this).get(RecordingViewModel.class);
recordingViewModel.getAllRecordings().observe(this, new Observer<List<Recording>>() {
@Override
public void onChanged(List<Recording> recordings) {
recordingsRecyclerViewAdapter.setRecordingsList(recordings);
}
});
}
public class PatientRepository {
private MedicationDao medicationDao;
private BPcheckDao bpCheckDao;
private LiveData<List<Medication>> allMedications;
private LiveData<List<MedTaken>> allMedTaken;
private LiveData<List<BPcheck>> allBPchecks;
public PatientRepository(Application application){
PatientDatabase database = PatientDatabase.getInstance(application);
medTakenDao= database.medTakenDao();
allMedTaken = medTakenDao.getAllMedTaken();
bpCheckDao= database.bpCheckDao();
allBPchecks = bpCheckDao.getAllBPchecks();
}
// MedTaken Methods
public void addToMedTaken(MedTaken medTaken){
new InsertMedTakenAsyncTask(medTakenDao).execute(medTaken);
}
public void updateMedTaken(MedTaken medTaken){
new UpdateMedTakenAsyncTask(medTakenDao).execute(medTaken);
}
public void deleteMedTaken(MedTaken medTaken){
new DeleteMedTakenAsyncTask(medTakenDao).execute(medTaken);
}
public LiveData<List<MedTaken>> getAllMedTaken() {
return allMedTaken;
}
// MedTaken ASYNC Tasks
private static class InsertMedTakenAsyncTask extends AsyncTask<MedTaken,Void,Void>{
private MedTakenDao medTakenDao;
private InsertMedTakenAsyncTask(MedTakenDao medTakenDao){
this.medTakenDao = medTakenDao;
}
@Override
protected Void doInBackground(MedTaken... medTaken) {
medTakenDao.insert(medTaken[0]);
return null;
}
}
private static class UpdateMedTakenAsyncTask extends AsyncTask<MedTaken,Void,Void>{
private MedTakenDao medTakenDao;
private UpdateMedTakenAsyncTask(MedTakenDao medTakenDao){
this.medTakenDao = medTakenDao;
}
@Override
protected Void doInBackground(MedTaken... medTaken) {
medTakenDao.update(medTaken[0]);
return null;
}
}
private static class DeleteMedTakenAsyncTask extends AsyncTask<MedTaken,Void,Void>{
private MedTakenDao medTakenDao;
private DeleteMedTakenAsyncTask(MedTakenDao medTakenDao){
this.medTakenDao = medTakenDao;
}
@Override
protected Void doInBackground(MedTaken... medTaken) {
medTakenDao.delete(medTaken[0]);
return null;
}
}
//BP Checks methods
public void addToBPchecks(BPcheck bpCheck){
new InsertBPchecksAsyncTask(bpCheckDao).execute(bpCheck);
}
public void updateBPchecks(BPcheck bpCheck){
new UpdateBPchecksAsyncTask(bpCheckDao).execute(bpCheck);
}
public void deleteBPchecks(BPcheck bpCheck){
new DeleteBPchecksAsyncTask(bpCheckDao).execute(bpCheck);
}
public LiveData<List<BPcheck>> getAllBPchecks() {
return allBPchecks;
}
// BPChecks ASYNC Tasks
private static class InsertBPchecksAsyncTask extends AsyncTask<BPcheck,Void,Void>{
private BPcheckDao bpCheckDao;
private InsertBPchecksAsyncTask(BPcheckDao bpCheckDao){
this.bpCheckDao = bpCheckDao;
}
@Override
protected Void doInBackground(BPcheck... bpChecks) {
bpCheckDao.insert(bpChecks[0]);
return null;
}
}
private static class UpdateBPchecksAsyncTask extends AsyncTask<BPcheck,Void,Void>{
private BPcheckDao bpCheckDao;
private UpdateBPchecksAsyncTask(BPcheckDao bpCheckDao){
this.bpCheckDao = bpCheckDao;
}
@Override
protected Void doInBackground(BPcheck... bpChecks) {
bpCheckDao.update(bpChecks[0]);
return null;
}
}
private static class DeleteBPchecksAsyncTask extends AsyncTask<BPcheck,Void,Void>{
private BPcheckDao bpCheckDao;
private DeleteBPchecksAsyncTask(BPcheckDao bpCheckDao){
this.bpCheckDao = bpCheckDao;
}
@Override
protected Void doInBackground(BPcheck... bpChecks) {
bpCheckDao.delete(bpChecks[0]);
return null;
}
}
@Entity(tableName = "BPcheck_table")
public class BPcheck {
@PrimaryKey(autoGenerate = true)
private int id;
private String date;
private String timestamp;
private int systolicBP;
private int diastolicBP;
private String comments;
public BPcheck(String date, String timestamp, int systolicBP, int diastolicBP, String comments) {
this.date = date;
this.timestamp = timestamp;
this.systolicBP = systolicBP;
this.diastolicBP = diastolicBP;
this.comments = comments;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public int getSystolicBP() {
return systolicBP;
}
public void setSystolicBP(int systolicBP) {
this.systolicBP = systolicBP;
}
public int getDiastolicBP() {
return diastolicBP;
}
public void setDiastolicBP(int diastolicBP) {
this.diastolicBP = diastolicBP;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
}
@Dao
public interface BPcheckDao {
@Insert
void insert(BPcheck BPcheck);
@Update
void update(BPcheck BPcheck);
@Delete
void delete(BPcheck BPcheck);
@Query("SELECT * FROM BPcheck_table")
LiveData<List<BPcheck>> getAllBPchecks();
}
public class RecordingsViewModel extends AndroidViewModel {
private PatientRepository repository;
private LiveData<List<MedTaken>> allMedTaken;
private LiveData<List<BPcheck>> allBPChecks;
private MediatorLiveData allRecordings;
public RecordingsViewModel(@NonNull Application application) {
super(application);
repository = new PatientRepository(application);
}
public LiveData<List<Object>> getAllRecordings() {
return allRecordings;
}
}
@Entity(tableName = "MedTaken_table")
public class MedTaken {
private int id;
private Medication medication;
private String comments;
private String date;
private String timestamp;
public MedTaken(Medication medication, String comments, String date, String timestamp) {
this.medication = medication;
this.comments = comments;
this.date = date;
this.timestamp = timestamp;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Medication getMedication() {
return medication;
}
public void setMedication(Medication medication) {
this.medication = medication;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
}
@Dao
public interface MedTakenDao {
@Insert
void insert(MedTaken medTaken);
@Update
void update(MedTaken medTaken);
@Delete
void delete(MedTaken medTaken);
@Query("SELECT * FROM MedTaken_table")
LiveData<List<MedTaken>> getAllMedTaken();
}
public class MedTakenViewModel extends AndroidViewModel {
private PatientRepository repository;
private LiveData<List<MedTaken>> allMedTaken;
public MedTakenViewModel(@NonNull Application application) {
super(application);
repository = new PatientRepository(application);
allMedTaken = repository.getAllMedTaken();
}
public void insert(MedTaken medTaken){ repository.addToMedTaken(medTaken); }
public void update(MedTaken medTaken){ repository.updateMedTaken(medTaken); }
public void delete(MedTaken medTaken){ repository.deleteMedTaken(medTaken); }
public LiveData<List<MedTaken>> getAllMedTaken() {
return allMedTaken;
}
}