当前位置:网站首页>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
边栏推荐
- 2. Sensor size "recommended collection"
- 北斗通信模块 北斗gps模块 北斗通信终端DTU
- 04 redis source code data structure dictionary
- Three questions about scientific entrepreneurship: timing, pain points and important decisions
- Judea pearl, Turing prize winner: 19 causal inference papers worth reading recently
- 基于mysql乐观锁实现秒杀的示例代码
- Nexus builds NPM dependent private database
- Simple two ball loading
- What is the future development direction of people with ordinary education, appearance and family background? The career planning after 00 has been made clear
- IO的几种模型 阻塞,非阻塞,io多路复用,信号驱动和异步io
猜你喜欢

研发效能度量框架解读

孔松(信通院)-数字化时代云安全能力建设及趋势

Simple two ball loading

波浪动画彩色五角星loader加载js特效

流量管理技术

Svg diamond style code

MySQL statistical bill information (Part 2): data import and query

一文读懂TDengine的窗口查询功能

The best landing practice of cave state in an Internet ⽹⾦ financial technology enterprise

Google Earth engine (GEE) - Global Human Settlements grid data 1975-1990-2000-2014 (p2016)
随机推荐
6. Wiper part
Asp. NETCORE uses dynamic to simplify database access
关于佛萨奇2.0“Meta Force原力元宇宙系统开发逻辑方案(详情)
Spark source code (V) how does dagscheduler taskscheduler cooperate with submitting tasks, and what is the corresponding relationship between application, job, stage, taskset, and task?
Application of 5g industrial gateway in scientific and technological overload control; off-site joint law enforcement for over limit, overweight and overspeed
What is the future development direction of people with ordinary education, appearance and family background? The career planning after 00 has been made clear
arthas使用
彩色五角星SVG动态网页背景js特效
5G工业网关的科技治超应用 超限超重超速非现场联合执法
Svg diamond style code
Simplex, half duplex, full duplex, TDD and FDD
Word2vec training Chinese word vector
Anti fraud, refusing to gamble, safe payment | there are many online investment scams, so it's impossible to make money like this
Analysis report on the development prospect and investment strategic planning of China's wafer manufacturing Ⓔ 2022 ~ 2028
MySQL Replication中的并行复制示例详解
运行游戏时出现0xc000007b错误的解决方法[通俗易懂]
Chen Yu (Aqua) - Safety - & gt; Cloud Security - & gt; Multicloud security
Colorful five pointed star SVG dynamic web page background JS special effect
面试题目总结(1) https中间人攻击,ConcurrentHashMap的原理 ,serialVersionUID常量,redis单线程,
Reasons for MySQL reporting 1040too many connections and Solutions