Databinding not observe LiveData in ViewModel

Viewed 2799

I am trying to use Data binding with LiveData in ViewModel. But when using Transformations.map functions not trigged without adding observers explicitly. Data binding in XML not generate observers for LiveData in ViewModel.

LoginFragment.kt

class LoginFragment : Fragment() {

    var homeViewModel: HomeViewModel? = null

    companion object {
        val TAG : String = "LoginFragment"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        homeViewModel = ViewModelProviders.of(this).get(HomeViewModel::class.java)
    }


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val binding = DataBindingUtil.inflate<FragmentLoginBinding>(inflater, R.layout.fragment_login, container, false)
                .apply {
                    setLifecycleOwner(this@LoginFragment)
                    loginButton.setOnClickListener {
                        signInWithEmail()
                    }
        }

        return binding.root
    }

    /*private fun observeHomeFragmentUIDataLiveData() {
        homeViewModel?.homeFragmentUIDataLiveData?.observe(this, Observer {
            val email = it.email
            Toast.makeText(activity,email, Toast.LENGTH_SHORT).show()
        })
    }

    private fun observeLoginErrorEventLiveData() {
        homeViewModel?.loginErrorEventLiveData?.observe(this, Observer {
            Toast.makeText(activity,it, Toast.LENGTH_SHORT).show()
        })
    }*/

    /**
     * Sign In via Email
     */
    fun signInWithEmail(){
        val email = email_text_input_layout.editText?.text.toString()
        val password = password_text_input_layout.editText?.text.toString()

        var cancel : Boolean? = false
        var focusView : View? = null

        if(password.isEmpty()){
            password_text_input_layout.error = getString(R.string.this_field_is_required)
            focusView = password_text_input_layout
            cancel = true
        }

        if(email.isEmpty()){
            email_text_input_layout.error = getString(R.string.this_field_is_required)
            focusView = email_text_input_layout
            cancel = true
        }

        if(cancel!!){
            focusView?.requestFocus()
        }
        else{
            homeViewModel?.signInWithEmail(email,password)

            /*homeViewModel?.signInWithEmail(email,password)?.observe(this, Observer {
                val email = it
                Toast.makeText(activity,""+email, Toast.LENGTH_SHORT).show()
            })*/
        }
    }
}

fragment_login.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable name="homeViewModel" type="com.rramprasad.adminapp.HomeViewModel"/>
    </data>

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="LoginFragment">

<!-- Skipped some code for clarity -->

<androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/error_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{homeViewModel.loginErrorEventLiveData.value}"
        app:isGone="@{homeViewModel.isLoginSuccess}"
        android:textColor="@android:color/holo_orange_dark"
        android:textSize="16sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/password_text_input_layout"
        app:layout_constraintBottom_toBottomOf="@id/login_button"
        />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

HomeViewModel.kt

class HomeViewModel(application: Application) : AndroidViewModel(application) {

    val homeRepository: HomeRepository?

    init {
        homeRepository = HomeRepository()
    }

    // UI Data for HomeFragment
    val homeFragmentUIDataLiveData : MutableLiveData<HomeFragmentUIData> = MutableLiveData()

    // UI Data for LoginFragment
    val loginErrorEventLiveData : MutableLiveData<String> = MutableLiveData()

    var isLoginSuccess: LiveData<Boolean>? = null

    fun signInWithEmail(email: String, password: String) : LiveData<Boolean>? {
        val signInResponseMutableLiveData : MutableLiveData<Any> = homeRepository?.signInWithEmail(email, password)!!

        isLoginSuccess = Transformations.map(signInResponseMutableLiveData) { signInResponse ->
            when (signInResponse) {
                (signInResponse is FirebaseUser) -> {
                    val firebaseUserEmail = (signInResponse as FirebaseUser).email
                    homeFragmentUIDataLiveData.value = HomeFragmentUIData(firebaseUserEmail ?: "")
                    return@map true
                }
                else -> {
                    loginErrorEventLiveData.value = signInResponse.toString()
                    return@map false
                }
            }
        }

        return isLoginSuccess
    }
}

BindingAdapters.kt

@BindingAdapter("isGone")
fun bindIsGone(view: View, isGone: Boolean) {
    view.visibility = if (isGone) {
        View.GONE
    } else {
        View.VISIBLE
    }
}

Android studio version:

Android Studio 3.2 RC 3
Build #AI-181.5540.7.32.4987877, built on August 31, 2018
JRE: 1.8.0_152-release-1136-b06 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
macOS 10.13.4

build.gradle:

android {
    compileSdkVersion 28
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    dataBinding {
        enabled = true
    }
}
0 Answers
Related