Search code examples
javaandroidtransformationandroid-livedataswitchmap

Chaining Multiple Transformations.switchMap off of one LiveData source


I'm learning Android for a school project, we have to use Java and we can't use any external libraries. I am creating a college student course load tracking app. Currently, I am working on the activity that will detail the information for a Course chosen by the user. I need to be able to fetch several database results when the user chooses a Course: the Mentor (Instructor), a LiveData List of Assessments, and a LiveData List of Notes. I currently have a Transformations.switchMap set up and working to get the Course Mentor. However, it appears a LiveData can only have one of this transformation observers on it. Here's my code:

CourseDetailViewModel

LiveData<Course> currentCourse;
LiveData<Mentor> courseMentor;
LiveData<List<Assessment>> courseAssessments;
LiveData<List<Note>> courseNotes;
final CourseDetailRepository REPO;

public CourseDetailViewModel(@NonNull Application application) {

    REPO = new CourseDetailRepository(application);
}

public LiveData<Course> getCurrentCourse(long id) {

    if (currentCourse == null) {
        currentCourse = REPO.getCourseById(id);
    }

    // I'm dong the Transformations here because I tried in the Constructor but because currentCourse
    // was null, the transformation wasn't kicking off.
    // the courseMentor Transformation works, the others don't seem to fire.
    courseMentor = Transformations.switchMap(curentCourse, course -> 
        REPO.getMentorById(course.getMentorId()));

    courseAssessments = Transformations.switchMap(currentCourse, course -> 
        REPO.getAssessmentsByCourse(course.getCourseId()));

    courseNotes = Transformations.switchMap(currentCourse, course -> 
        REPO.getNotesByCourse(course.getCourseId())));

    return this.currentCourse;
}

public LiveData<Mentor> getCourseMentor() { return this.courseMentor }

public LiveData<List<Assessment>> getCourseAssessments() { return this.courseAssessments }

public LiveData<List<Note>> getCourseNotes() { return this.courseNotes }

I then observe these LiveData objects in my CourseDetailActivity to populate the UI: Mentor populates a sets the selection of a Spinner, List<Assessment> and List<Note> are passed into their respective RecyclerView Adapters.

I have a feeling I could use something like MediatorLiveData but, I really don't fully understand how to properly use it, even after reviewing many resources online. I'm new to Android, this is my very first Android project, so I know I have a lot to learn and I am totally open to criticism on design decisions.

Thank you so much for your assistance!


Solution

  • Ok so, I was able to figure it out! By adding a MutableLiveData<Long> to hold the ID used to retrieve the Course from the database, I'm able to set the value from the the getCourseById(long id) which triggers the first Transformations.switchMap to get CURRENT_COURSE which sets off the other Transformations.switchMaps for COURSE_MENTOR, COURSE_ASSESSMENTS and COURSE_NOTES.

    Someone had suggested somewhere else that I pass the ID in via the ViewModel Constructor and use a custom ViewModelFactory, which is something I will look into in the future. Right now, I need to get this submitted ;).

    I hope this helps someone else!

    CourseDetailViewModel

    final MutableLiveData<Long> CURRENT_COURSE_ID;
    final LiveData<Course> CURRENT_COURSE;
    final LiveData<Mentor> COURSE_MENTOR;
    final LiveData<List<Assessment>> COURSE_ASSESSMENTS;
    final LiveData<List<Note>> COURSE_NOTES;
    final CourseDetailRepository REPO;
    
    public CourseDetailViewModel(@NonNull Application application) {
    
        REPO = new CourseDetailRepository(application);
    
        CURRENT_COURSE_ID = new MutableLiveData<>();
    
        CURRENT_COURSE = Transformations.switchMap(CURRENT_COURSE_ID, 
            COURSE_ID -> REPO.getCourseById(COURSE_ID));
    
        COURSE_MENTOR = Transformations.switchMap(CURRENT_COURSE, 
            COURSE -> REPO.getMentorById(COURSE.getMentorId()));
    
        COURSE_ASSESSMENTS = Transformations.switchMap(CURRENT_COURSE, 
            COURSE -> REPO.getAssessmentsByCourse(COURSE.getCourseId()));
    
        COURSE_NOTES = Transformations.switchMap(CURRENT_COURSE, 
            COURSE -> REPO.getNotesByCourse(COURSE.getCourseId())));
    }
    
    public LiveData<Course> getCurrentCourse(long id) {
        CURRENT_COURSE_ID.setValue(id);
        return this.CURRENT_COURSE;
    }
    
    public LiveData<Mentor> getCourseMentor() { return this.COURSE_MENTOR}
    
    public LiveData<List<Assessment>> getCourseAssessments() { return this.COURSE_ASSESSMENTS}
    
    public LiveData<List<Note>> getCourseNotes() { return this.COURSE_NOTES}