当前位置:网站首页>Learning to use livedata and ViewModel will make it easier for you to write business
Learning to use livedata and ViewModel will make it easier for you to write business
2022-07-01 13:34:00 【InfoQ】
Preface :
Introduce
LiveData and ViewModel The relationship between :

LiveData
Use LiveData It has the following advantages :
- UI Match data status
- LiveData Follow the observer pattern . When the underlying data changes ,LiveData Will inform
Observerobject . You can integrate the code in theseObserverObject to update the interface . thus , You don't need to update the interface every time the application data changes , Because the observer will complete the update for you .
- Improve code stability
- Code stability increases throughout the application lifecycle :
- There is no crash when the activity stops . If the application component is inactive , Then these changes are not affected . therefore , You don't have to worry about the lifecycle of application components when updating data . For activities in the background stack , It will not accept any LiveData event
- Memory leaks are reduced , The observer will be bound to Lifecycle object , And self cleaning after its associated life cycle has been destroyed
- Don't worry about unsubscribing from any observer
- If due to configuration changes ( If the equipment rotates ) And recreated Activity or Fragment, It will immediately receive the latest available data .
- No longer need to manually handle the lifecycle
- Interface components just look at relevant data , Does not stop or resume observation .LiveData All of these operations will be managed automatically , Because it can sense the change of related life cycle state when observing .
- Data is always up to date
- If the life cycle becomes inactive , It receives the latest data when it becomes active again . for example , Used to be backstage Activity It will receive the latest data immediately after returning to the foreground .
- Shared resources
- Like the singleton mode , We can also expand our LiveData Object to wrap system services , So that they can be shared in our application . once LiveData Object to connect to system services , Any observer who needs resources can easily watch LiveData object .
In the following cases , Do not use LiveData:
- You need to use a lot of operators on Information , Even though LiveData Provides tools such as transformations , But only Map and switchMap Can help you
- You don't have any contact with information UI Interaction
- You have a one-time asynchronous operation
- You do not have to save cached information to UI in
How to use LiveData
Basic usage process :
class MainViewModel : ViewModel() {
var mycount: MutableLiveData<Int> = MutableLiveData()
}
class MainActivity : AppCompatActivity() {
lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
...
/** Remember that you can never create directly ViewModel example
Be sure to pass ViewModelProvider(ViewModelStoreOwner) Constructor to get .
Because every time you rotate the screen, you will recall onCreate() Method , If you create a new instance every time, you cannot save the data .
After using the above method ,onCreate Method is called again ,
It will return an and MainActivity Associated with a preexisting ViewModel, That's why you save data .*/
viewModel = ViewModelProvider([email protected],ViewModelProvider.
NewInstanceFactory()).get(MainViewModel::class.java)
}
}
/**
* subscribe ViewModel,mycount It's a LiveData type You can observe
* */
viewModel.mycount.observe([email protected]) {
countTv.text = viewModel.mycount.value.toString()
}
// LiveData onchange Will automatically sense the lifecycle No manual operation required
// viewModel.mycount.observe(this, object : Observer<Int> {
// override fun onChanged(t: Int?) {
//
// }
// })
Advanced usage :
// Entity class
data class User(var name: String)
...
//Transformations.map Receive two parameters , The first parameter is for the transformation LiveData The original object , The second parameter is the conversion function .
private val userLiveData: MutableLiveData<User> = MutableLiveData()
val userNames: LiveData<String> = Transformations
.map(userLiveData) { user ->
user.name
}
data class Student
(var englishScore: Double, var mathScore: Double, val scoreTAG: Boolean)
.....
class SwitchMapViewModel:ViewModel {
var studentLiveData = MutableLiveData<Student>()
val transformationsLiveData = Transformations.switchMap(studentLiveData) {
if (it.scoreTAG) {
MutableLiveData(it.englishScore)
} else {
MutableLiveData(it.mathScore)
}
}
}
// When using :
var student = Student()
person.englishScore = 88.2
person.mathScore = 91.3
// Decide which grade to show
person.condition = true
switchMapViewModel.conditionLiveData.postValue(person)
class MediatorLiveDataViewModel : ViewModel() {
var liveDataA = MutableLiveData<String>()
var liveDataB = MutableLiveData<String>()
var mediatorLiveData = MediatorLiveData<String>()
init {
mediatorLiveData.addSource(liveDataA) {
Log.d("This is livedataA", it)
mediatorLiveData.postValue(it)
}
mediatorLiveData.addSource(liveDataB) {
Log.d("This is livedataB", it)
mediatorLiveData.postValue(it)
}
}
}
explain :
- MutableLiveData The parent class is LiveData
- LiveData In the entity class, you can notify the data update of a specified field
- MutableLiveData It is only notified after the entire entity class or data type changes . Details will not be to a field .
Principle Exploration :
- LiveData How it works
- LiveData Of observe Method source code analysis
- LifecycleBoundObserver Source code analysis
- activeStateChanged Source code analysis ( For sticky events )
- postValue and setValue
- considerNotify Determine whether to send data analysis
- Analysis of viscous events
ViewModel
Official profile
Life cycle

Basic usage process :
class MainViewModel : ViewModel() {
...
}
// The first one is ViewModelProvider Direct access to
ViewModelProvider([email protected]).get(MainViewModel::class.java)
// The second kind adopt ViewModelFactory establish
class TestViewModelFactory(private val param: Int) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return TestViewModel(param) as T
}
}
ViewModelProvider([email protected],TestViewModelFactory(0)).get(TestViewModel::class.java)
ViewModel Common use scenarios
- Use ViewModel, After switching between horizontal and vertical screens ,Activity The reconstruction , Data can still be saved
- The same Activity Next ,Fragment Data sharing between
- And LiveData Cooperate to realize code decoupling
ViewModel and onSaveInstanceState The difference between
ViewModel and Context
Case a : Counter — Two Activity Share a ViewModel

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MainViewModel : ViewModel() {
private var _mycount: MutableLiveData<Int> = MutableLiveData()
// Expose only immutable LiveData Externally
val mycount: LiveData<Int> get() = _mycount
init {
// initialization
_mycount.value = 0
}
/**
* mycount.value If it is empty, it will be assigned as 0, If it is not empty, add one
* */
fun add() {
_mycount.value = _mycount.value?.plus(1)
}
/**
* mycount.value If it is empty, it will be assigned as 0, If it is not empty, subtract one , Can be negative
* */
fun reduce() {
_mycount.value = _mycount.value?.minus(1)
}
/**
* Random parameter
* */
fun random() {
val random = (0..100).random()
_mycount.value = random
}
/**
* Clear data
* */
fun clear() {
_mycount.value = 0
}
}
import androidx.lifecycle.*
/**
* Used to mark viewmodel Scope of action
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
annotation
class VMScope(val scopeName: String) {}
private val vMStores = HashMap<String, VMStore>()
fun LifecycleOwner.injectViewModel() {
// Create a store according to the scope
this::class.java.declaredFields.forEach { field ->
field.getAnnotation(VMScope::class.java)?.also { scope ->
val element = scope.scopeName
var store: VMStore
if (vMStores.keys.contains(element)) {
store = vMStores[element]!!
} else {
store = VMStore()
vMStores[element] = store
}
val clazz = field.type as Class<ViewModel>
val vm = ViewModelProvider(store, ViewModelProvider.NewInstanceFactory()).get(clazz)
field.set(this, vm)
}
}
}
class VMStore : ViewModelStoreOwner {
private var vmStore: ViewModelStore? = null
override fun getViewModelStore(): ViewModelStore {
if (vmStore == null)
vmStore = ViewModelStore()
return vmStore!!
}
}
class MainActivity : AppCompatActivity() {
@VMScope("count") // Set scope
lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
injectViewModel()
initEvent()
}
private fun initEvent() {
val cardReduce: CardView = findViewById(R.id.card_reduce)
.....
cardReduce.setOnClickListener {
// Call custom ViewModel The method in
viewModel.reduce()
}
.....
/**
* subscribe ViewModel,mycount It's a LiveData type You can observe
* */
viewModel.mycount.observe([email protected]) {
countTv.text = viewModel.mycount.value.toString()
}
}
In the second Activity The same is true of ...
Case 2 : The same Activity Of the two Fragment Share a ViewModel

class BlankViewModel : ViewModel() {
private val numberLiveData = MutableLiveData<Int>()
private var i = 0
fun getLiveData(): LiveData<Int> {
return numberLiveData
}
fun addOne(){
i++
numberLiveData.value = i
}
}
// Left Fragment
class LeftFragment : Fragment() {
private val viewModel:BlankViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_left, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Yes +1 Button monitoring
left_button.setOnClickListener {
viewModel.addOne()
}
activity?.let {it ->
viewModel.getLiveData().observe(it){
left_text.text = it.toString()
}
}
}
}
// Right Fragment
class RightFragment : Fragment() {
private val viewModel: BlankViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_right, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
right_button.setOnClickListener {
viewModel.addOne()
}
activity?.let { it ->
viewModel.getLiveData().observe(it) {
right_text.text = it.toString()
}
}
}
}
Epilogue
About me
边栏推荐
- MySQL statistical bill information (Part 2): data import and query
- Investment analysis and prospect prediction report of global and Chinese p-nitrotoluene industry Ⓙ 2022 ~ 2027
- 关于佛萨奇2.0“Meta Force原力元宇宙系统开发逻辑方案(详情)
- 一文读懂TDengine的窗口查询功能
- MySQL 66 questions, 20000 words + 50 pictures in detail! Necessary for review
- What is the future development direction of people with ordinary education, appearance and family background? The career planning after 00 has been made clear
- Simple two ball loading
- Leetcode question 1: sum of two numbers (3 languages)
- A Fletter version of Notepad
- 一款Flutter版的记事本
猜你喜欢

MySQL 66 questions, 20000 words + 50 pictures in detail! Necessary for review

1553B环境搭建

What is the future development direction of people with ordinary education, appearance and family background? The career planning after 00 has been made clear

JS discolored Lego building blocks

终端识别技术和管理技术

ZABBIX 6.0 source code installation and ha configuration

Introduction to reverse debugging PE structure input table output table 05/07

Terminal identification technology and management technology

Beidou communication module Beidou GPS module Beidou communication terminal DTU

minimum spanning tree
随机推荐
Simplex, half duplex, full duplex, TDD and FDD
微机原理与接口技术知识点整理复习–纯手打
面试题目总结(1) https中间人攻击,ConcurrentHashMap的原理 ,serialVersionUID常量,redis单线程,
Example code of second kill based on MySQL optimistic lock
刘对(火线安全)-多云环境的风险发现
Global and Chinese polypropylene industry prospect analysis and market demand forecast report Ⓝ 2022 ~ 2027
龙蜥社区开源 coolbpf,BPF 程序开发效率提升百倍
Anti fraud, refusing to gamble, safe payment | there are many online investment scams, so it's impossible to make money like this
2. Sensor size "recommended collection"
Sharing with the best paper winner of CV Summit: how is a good paper refined?
word2vec训练中文词向量
Research Report on China's software outsourcing industry investment strategy and the 14th five year plan Ⓡ 2022 ~ 2028
Build a vc2010 development environment and create a tutorial of "realizing Tetris game in C language"
Terminal identification technology and management technology
启动solr报错The stack size specified is too small,Specify at least 328k
04-Redis源码数据结构之字典
MySQL六十六问,两万字+五十图详解!复习必备
minimum spanning tree
Arthas use
关于佛萨奇2.0“Meta Force原力元宇宙系统开发逻辑方案(详情)