Search code examples
androidandroid-livedataandroid-viewmodelapollo-android

Best approach to waiting on pending live data using architecture components


I'm working on an application that fetches data from a graphql server via apollo-android.

I do a single fetch on my aws rds database. I do this fetch right at the onCreate() of my CalendarFragment.

The thing is, at onViewCreated(), I want to set my textview to one of the fields that is fetched, first and last name. So, I run my getBarberFullName method which returns the String value of mBarberFullName. I'm trying to follow the UI controller displays while the view model handles all the logic approach. getBarberFullName resides within my ViewModel.

    public String getBarberFullName() {
        if (appointmentsAreNull()) return mBarberFullName.getValue();
        AppointmentModel am = mMasterAppointments.getValue().get(0);
        String fullName = am.bFirstName;
        fullName = fullName.concat(" " + am.bLastName);
        // Get the logged in barber's full name and set it as mBarberFullName.
        mBarberFullName.setValue(fullName);
        return mBarberFullName.getValue();
    }

where mMasterAppointments is a MutableLiveData<List<AppointmentModel>>. In my onViewCreated() callback, I run

String barberName = mBarberViewModel.getBarberFullName();
        mTxtv_barberName.setText(barberName);

However, mMasterAppointments is always null so it just returns the default value of mBarberFullName which is a String.

However, if I were to run the following code, in the same onViewCreated(), I get the desired result where the textview is updated with the desired barber's full name.

  mBarberViewModel.getAllAppointments().observe(getViewLifecycleOwner(), am -> {
            if (am.isEmpty()) {
                Log.d(TAG, "No barber.");
                return;
            }
            String barberGreeting;
            barberGreeting = am.get(0).bFirstName;
            barberGreeting = barberGreeting.concat(" " + am.get(0).bLastName);
            mTxtv_barberName.setText(barberGreeting);
        });

getAllAppointments returns an observer to mMasterAppointments located in my ViewModel.

Although getAllAppointments and getBarberFullName are called within onViewCreated(), one is able to access the pending values of mMasterAppointments while the other is not. Why?

I don't want to do the logic in my Fragments onViewCreated callback, so how can I wait on the pending mMasterApointmentData in my ViewModel's getBarberFullName()? Are there tools within LiveData and ViewModel that would aid me in this situation?


Solution

  • Use LiveData's Transformations class

    when you need to perform calculations, display only a subset of the data, or change the rendition of the data.

    First add a new String LiveData for BarberFullName in the viewmdoel, and give it the value of transforming (mapping) the source LiveData mMasterAppointments into the desired String:

    val fullBarberName: LiveData<String> = Transformations.map(mMasterAppointments) { am ->
             " ${am[0].bFirstName} ${am.get(0).bLastName}" 
    }
    

    Now you can observe this String LiveData in your fragment, the way you in did your second snippet.

    Note that the code I provided is in Kotlin, I use it nowadays. I hope you get it.