efoc
efoc

Reputation: 641

Android: Why doesn't this Transformation.map run when trying to assign to a variable?

I am trying to use the Firebase API in my project but Transformations.map for the variable authenticationState in the View Model does not run. I have been following Google's tutorial here (link goes to the ViewModel of that project).

I want to be able to add the Transformations.map code to the FirebaseUserLiveData file later but I cant seem to figure out why it doesn't run.

FirebaseUserLiveData

class FirebaseUserLiveData: LiveData<FirebaseUser?>() {

    private val firebaseAuth = FirebaseAuth.getInstance()
    private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
        value = firebaseAuth.currentUser
    }


    override fun onActive() {
        firebaseAuth.addAuthStateListener { authStateListener }
    }

    override fun onInactive() {
        firebaseAuth.removeAuthStateListener(authStateListener)
    }
}

SearchMovieFragmentViewModel

class SearchMovieFragmentViewModel : ViewModel() {

    enum class AuthenticationState {
        AUTHENTICATED, UNAUTHENTICATED, INVALID_AUTHENTICATION
    }

    var authenticationState = Transformations.map(FirebaseUserLiveData()) { user ->
        Log.d("TEST", "in the state function")
        if (user != null) {
            AuthenticationState.AUTHENTICATED
        } else {
            AuthenticationState.UNAUTHENTICATED
        }
    }

SearchMovieFragment

class SearchMovieFragment : Fragment(), MovieSearchItemViewModel {

    companion object {
        fun newInstance() = SearchMovieFragment()
    }

    private lateinit var searchMovieFragmentViewModel: SearchMovieFragmentViewModel
    private lateinit var binding: SearchMovieFragmentBinding
    private lateinit var movieRecyclerView: RecyclerView

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        binding = DataBindingUtil.inflate(inflater, R.layout.search_movie_fragment, container, false)
        searchMovieFragmentViewModel = ViewModelProvider(this).get(SearchMovieFragmentViewModel::class.java)
        binding.lifecycleOwner = this
        binding.viewmodel = searchMovieFragmentViewModel

        binding.signOutButton.setOnClickListener {
            AuthUI.getInstance().signOut(requireContext())
        }

        searchMovieFragmentViewModel.authenticationState.observe(viewLifecycleOwner, Observer { state ->
            when (state) {
                AUTHENTICATED -> searchMovieFragmentViewModel.signedIn = View.VISIBLE
                UNAUTHENTICATED -> searchMovieFragmentViewModel.signedIn = View.GONE
            }
        })
        return binding.root
    }
}

Upvotes: 1

Views: 300

Answers (2)

IR42
IR42

Reputation: 9732

Should be .addAuthStateListener(authStateListener) instead of { authStateListener }

Upvotes: 1

ObinasBaba
ObinasBaba

Reputation: 530

That is because you are not keeping the reference of FirebaseUserLiveData() once you start observing it like Transformations.map(FirebaseUserLiveData()) { user ->. You have to have the reference of the Livedata you are mapping or transferring to another form of Livedata.

It is like a chain of observation, All LiveData in the chain should be observed or should have some kind of observer down the line, The main use-case is to transform some form of livedata to something you want, For Example:

class YourRepository{  // your repo, that connected to a network that keeps up to date some data
  val IntegerResource: LiveData<Int> = SomeRetrofitInstance.fetchFromNetwork() //updating some resource from network
}

class YourViewModel{
  val repository = YourRepository()

 //this will start observe the repository livedata and map it to string resource
  var StringResource: Livedata<String> = Transformations.map( repository.IntegerResource ) { integerValue ->
    integerValue.toString()
}

My Point is you have to keep alive the LiveData you are transforming. Hope helped.

Upvotes: 0

Related Questions