AndroidX provides classes to implement the MVVM pattern.
The ViewModel is a class that is responsible for preparing and managing the data for an Activity or a Fragment. It also handles the communication of the Activity/Fragment with the rest of the application.
Best practice:
view model shouldn’t know anything about Android
view model shouldn't have references to the views (view models and views have different life cycle)
don’t put hard logic in the ViewModel, just work with a repository, i.e
with a class that manages multiple data sources like memory cache, web, db.
LiveData is an observable data holder class. Unlike a regular observable, it takes into account the lifecycle of other app components, such as activities, fragments, or services.
A LiveData object is usually stored within a ViewModel object.
class NameViewModel : ViewModel() {
// Create a LiveData with a String
val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
// ...
}
Add dependencies for viewmodel, lifecycle and live data
// Access composable APIs built on top of Activity.
// allows to init like
// private val model: MyModelView by viewModels()
val activity_version = "1.2.3"
// Java language implementation of activities
implementation ("androidx.activity:activity:$activity_version")
// Kotlin
implementation ("androidx.activity:activity-ktx:$activity_version")
val fragment_version = "1.3.4"
// Java language implementation of fragments
implementation("androidx.fragment:fragment:$fragment_version")
// Kotlin
implementation("androidx.fragment:fragment-ktx:$fragment_version")
val lifecycle_version = "2.3.1"
val arch_version = "2.1.0"
// ViewModel
implementation ("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")
// LiveData
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")
// Lifecycles only (without ViewModel or LiveData)
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version")
// Saved state module for ViewModel
implementation ("androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version")
// Jetpack Compose Integration for ViewModel
implementation ("androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha04")
// for Java 8+
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// annotation processor before Java 8
// kapt ("androidx.lifecycle:lifecycle-compiler:$lifecycle_version")
// optional - helpers for implementing
// LifecycleOwner in a Service
// implementation ("androidx.lifecycle:lifecycle-service:$lifecycle_version")
// optional - ProcessLifecycleOwner provides
// a lifecycle for the whole application process
// implementation ("androidx.lifecycle:lifecycle-process:$lifecycle_version")
// optional - ReactiveStreams support for LiveData
// implementation ("androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version")
// optional - Test helpers for LiveData
// testImplementation ("androidx.arch.core:core-testing:$arch_version")
In most cases, an app component’s onCreate() method is the right place to begin observing a LiveData object.
class NameActivity : AppCompatActivity() {
// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
private val model: NameViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
// Create the observer which updates the UI.
val nameObserver = Observer<String> { newName ->
// Update the UI, in this case, a TextView.
nameTextView.text = newName
}
// Observe the LiveData, passing in this activity
// as the LifecycleOwner and the observer.
model.currentName.observe(this, nameObserver)
}
}
public class NameActivity extends AppCompatActivity {
private NameViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
// Get the ViewModel
model = new ViewModelProvider(this).get(NameViewModel.class);
// Create the observer which updates the UI.
final Observer<String> nameObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
nameTextView.setText(newName); // update the UI, in this case, a TextView.
}
};
// Observe the LiveData, passing in this activity
// as the LifecycleOwner and the observer.
model.getCurrentName().observe(this, nameObserver);
}
}
Fragments can get the activity viewmodel via activityViewModels() method.
Share viewmodel with fragments
class MainActivity : AppCompatActivity() {
private val viewModel: ItemViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.selectedItem.observe(this, Observer { item ->
// Perform an action with the latest item data
})
}
}
class ListFragment : Fragment() {
private val viewModel: ListViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.filteredList.observe(viewLifecycleOwner, Observer { list ->
// Update the list UI
})
}
}
class FilterFragment : Fragment() {
private val viewModel: ListViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.filters.observe(viewLifecycleOwner) { set ->
// Update the selected filters UI
}
}
fun onFilterSelected(filter: Filter) = viewModel.addFilter(filter)
fun onFilterDeselected(filter: Filter) = viewModel.removeFilter(filter)
}
A fragment can define its own view model and share it with a child fragment.
Fragment viewmodel
class ListFragment: Fragment() {
private val viewModel: ListViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.filteredList.observe(viewLifecycleOwner) { list ->
// Update the list UI
}
}
}
class ChildFragment: Fragment() {
private val viewModel: ListViewModel by viewModels({requireParentFragment()})
...
}