Overview of components
Jetpack is a suite of libraries to help developers follow best practices, reduce boilerplate code, and write code that works consistently across Android versions and devices so that developers can focus on the code.
Android Jetpack brings new approaches and components. Most valuable of them are
ViewModel
First of all add lifecycle-extensions
to the build.gradle file
dependencies { ... implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation "androidx.activity:activity-ktx:1.1.0" implementation "androidx.fragment:fragment-ktx:1.2.2" }
MoneyViewModel
class is inherited from the ViewModel Android architecture component.
class MoneyViewModel: ViewModel() { private val dollarRate = 0.74f private var dollarText = "" private var result: Float? = 0f fun setValue(value: String) { this.dollarText = value result = dollarText.toFloat() * dollarRate } fun getResult(): Float? { return result } }
Next step is add MoneyViewModel
to the Activity
via by viewModels()
delegate.
class VMActivity : AppCompatActivity() { val vm: MoneyViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_vm) tv.text = vm.getResult().toString() btn.setOnClickListener { if (et.text.isNotEmpty()) { vm.setValue(et.text.toString()) tv.text = vm.getResult().toString() } else { tv.text = "No value" } } } }
Following is content of activity_vm.xml layout
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" android:id="@+id/tv"/> <Button android:text="Get" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/tv" android:id="@+id/btn" android:layout_marginRight="8dp" android:layout_marginEnd="8dp" android:layout_marginLeft="8dp" android:layout_marginStart="8dp" android:layout_marginTop="32dp" android:visibility="visible"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="number" android:ems="10" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:id="@+id/et" app:layout_constraintBottom_toTopOf="@+id/tv" android:layout_marginBottom="32dp"/> </androidx.constraintlayout.widget.ConstraintLayout>
LiveData
LiveData
is an observable data holder. This allows the components in your app to be able to observe LiveData
objects for changes without creating explicit and tough dependency between them. UI view can receive a notification whenever the underlying LiveData value changes.
Edit the MoneyViewModel.kt file and wrap the result
variable in a MutableLiveData
instance
class MoneyViewModel: ViewModel() { private val dollarRate = 0.74f private var dollarText = "" private var result: MutableLiveData<Float> = MutableLiveData<Float>() fun setValue(value: String) { this.dollarText = value result.value = dollarText.toFloat() * dollarRate } fun getResult(): MutableLiveData<Float> { return result } }
The next step is to update MoneyActivity.kt file and add the observer to the result LiveData
object.
class MoneyActivity : AppCompatActivity() { val vm: MoneyViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_vm) val resultObserver: Observer<Float> = Observer { tv.text = it.toString() } vm.getResult().observe(this, resultObserver) btn.setOnClickListener { if (et.text.isNotEmpty()) { vm.setValue(et.text.toString()) } else { tv.text = "No value" } } } }
Passing data between Activity and Fragment
Following example shows one of the ways how to easily interact between Activity and Fragment. There is a ViewModel in the Activity and a Fragment want to publish some changes
class MovieViewModel { fun getView(): SomeView { ... } fun fetchData() { ... } } class MyActivity: Activity() { private val vm by viewModels<MovieViewModel>() override fun onResume() { updateView(vm.getView()) } } class SomeFragment: Fragment() { private val vm by activityViewModels<MovieViewModel>() fun onClick() { vm.fetchData() } }