Using Databinding, ViewModel, LiveData ( MVVM ). In my Layout there's a form to add Employee Details.
layout:
<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="viewModelAddEmployee"
type="com.app.roomemployeedemo.viewmodel.AddEmployeeViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/edt_lastname"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.AddEmployeeActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:text="@{viewModelAddEmployee.firstname}"
android:id="@+id/edt_firstname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:ems="10"
android:hint="Jaimin"
android:inputType="textPersonName"
android:maxLength="30"
android:maxLines="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:text="@{viewModelAddEmployee.lastname}"
android:id="@+id/tv_lastname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:ems="10"
android:hint="Modi"
android:inputType="textPersonName"
android:maxLength="30"
android:maxLines="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edt_firstname" />
<EditText
android:text="@{viewModelAddEmployee.age}"
android:id="@+id/edt_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:ems="10"
android:hint="25"
android:inputType="textPersonName"
android:maxLength="3"
android:maxLines="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_lastname" />
<EditText
android:text="@{viewModelAddEmployee.gender}"
android:id="@+id/edt_gender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:ems="10"
android:hint="Gender (M/F, m/f)"
android:inputType="textPersonName"
android:maxLength="1"
android:maxLines="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edt_age" />
<EditText
android:text="@{viewModelAddEmployee.salary}"
android:id="@+id/edt_salary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:ems="10"
android:hint="Salary (50000)"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edt_gender" />
<Button
android:onClick="@{(v) -> viewModelAddEmployee.onAddEmployeeClick(v)}"
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginTop="40dp"
android:layout_marginEnd="40dp"
android:text="ADD NOW"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edt_salary" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
Below is the ViewModel class for the same:
class AddEmployeeViewModel(mContext: Context) : ViewModel(){
var mContext=mContext
lateinit var firstname:MutableLiveData<String>
lateinit var lastname:MutableLiveData<String>
lateinit var age:MutableLiveData<Int>
lateinit var gender:MutableLiveData<Char>
lateinit var salary:MutableLiveData<Int>
lateinit var repositoryEmployee:EmployeeRepository
init{
repositoryEmployee= EmployeeRepository(mContext)
}
fun onAddEmployeeClick(view: View)
{
repositoryEmployee.onAddEmployeeClick(mContext,firstname,lastname,age,gender,salary)
}
}
Initialized Viewmodel and binding utility in Activity class as below:
class AddEmployeeActivity : AppCompatActivity() {
lateinit var viewModelAddEmployee: AddEmployeeViewModel
lateinit var binding: ActivityAddEmployeeBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModelAddEmployee = ViewModelProvider(this,AddEmployeeFactory(this@AddEmployeeActivity)).get(AddEmployeeViewModel::class.java)
binding = DataBindingUtil.setContentView(
this@AddEmployeeActivity,
R.layout.activity_add_employee
)
binding?.setLifecycleOwner(this)
binding?.viewModelAddEmployee = viewModelAddEmployee
}
}
But, Getting below Error:
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property gender has not been initialized
at com.app.roomemployeedemo.viewmodel.AddEmployeeViewModel.getGender(AddEmployeeViewModel.kt:16)
What might be the issue? Especially with Char type gender!!
You are declaring your live data objects as lateinit var
which means that you have to initialize them later before referring to them. You need to remove lateinit
and initialize when creating the ViewModel or initialize each live data field in your init
block like here:
firstname = MutableLiveData<>()
What you can do is this
fun returnName(): LiveData<String> {
if (firstname == null) {
firstname = MutableLiveData()
//call some function to set value to the variable
}
return firstname
}
This would ensure that you don't create multiple instances of that list and it would return the same instance eveytime. You can implement it on any variable you want
In kotlin you must initialize lateinit property. Add below line to oncreate -
gender = MutableLiveData<Char>()
Normally, properties declared as having a non-null type must be initialized in the constructor. However, fairly often this is not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit test. In this case, you cannot supply a non-null initializer in the constructor, but you still want to avoid null checks when referencing the property inside the body of a class.
To handle this case, you can mark the property with the lateinit modifier:
Sample
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // dereference directly
}
}
In your case, values must be loaded into variables in ViewModel.
In you case;
class AddEmployeeViewModel(mContext: Context) : ViewModel(){
var mContext=mContext
lateinit var firstname:MutableLiveData<String>
lateinit var lastname:MutableLiveData<String>
lateinit var age:MutableLiveData<Int>
lateinit var gender:MutableLiveData<Char>
lateinit var salary:MutableLiveData<Int>
lateinit var repositoryEmployee:EmployeeRepository
init{
repositoryEmployee= EmployeeRepository(mContext)
lastname = MutableLiveData<String>()
firstname = MutableLiveData<String>()
age = MutableLiveData<Int>()
gender = MutableLiveData<Char>()
salary = MutableLiveData<Int>()
}
fun onAddEmployeeClick(view: View)
{
repositoryEmployee.onAddEmployeeClick(mContext,firstname,lastname,age,gender,salary)
}
}
Best Practice
private val _sampleVar = MutableLiveData<String>()
val sampleVar: LiveData<String>
get() = _sampleVar
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.