当前位置: 首页 > Web前端 > HTML

AndroidJetpackLivedata应用场景分析

时间:2023-03-28 17:37:50 HTML

Livedata概述LiveData是一个可观察的数据存储类。与常规的可观察类不同,LiveData是生命周期感知的,如果观察者的生命周期处于STARTED或RESUMED状态,LiveData认为观察者(由Observer类表示)是活动的。.LiveData只会将更新通知活跃的观察者。注册观察LiveData对象的非活动观察者将不会收到更改通知。您可以注册与实现LifecycleOwner接口的对象配对的观察者。有了这种关系,当相应的Lifecycle对象的状态变为DESTROYED时,可以删除观察者。这对Activity和Fragments特别有用,因为它们可以安全地观察LiveData对象,而不必担心泄漏LiveData优势数据符合页面状态无内存泄漏不会因Activity停止而崩溃不再需要手动处理生命周期数据始终保持最新状态可以用于资源共享Livedata。一般来说,我们会在ViewModel中创建一个Livedata对象,然后在Activity/Fragment的onCreate中注册Livedata的监听器(因为在onStart和onResume中可能会有多余的监听调用)Livedata简单使用还是用我们的倒计时例子,在Viewmodel中开始2000秒倒计时,然后通过Livedata回调Activity更新界面,代码:viewmodelcodeclassCountDownModel:ViewModel(){valcountDownLivedata=MutableLiveData()privatevarremainSecond=2000//remainingsecondsinit{valcountDown=object:CountDownTimer(2000*1000,1000){overridefunonTick(millisUntilFinished:Long){remainSecond--countDownLivedata.postValue("remaining:${remainSecond}seconds")}overridefunonFinish(){countDownLivedata.postValue("Countdownends")}}countDown.start()}}活动中的观察数据更新ui代码valcountDownModel:CountDownModelbyviewModels{ViewModelProvider.NewInstanceFactory()}覆盖乐趣onCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContentView(R.layout.activity_count_down)countDownModel.countDownLivedata.observe(this,object:Observer{overridefunonChanged(value:String?){value?.let{tv_countdown_remainsecond.text=it}}})}效果图使用全局Livedata在多个视图中监控状态。本例实现的demo效果是创建一个全局倒计时,然后在Activity中添加两个按钮,点击后可以在FragmentA和FragmentB之间切换然后我们通过全局自定义的LiveData单例来实现数据监控。切换Fragment后,Fragment页面会显示倒计时剩余秒数。代码:全局自定义Livedata代码classGlobalLivedata:LiveData(){valcoundManager=CountDownManager()vallistener=object:OnDataChangeListener{overridefunchange(data:String){postValue(data)}}overridefunonActive(){super.onActive()coundManager.setListener(listener)}overridefunonInactive(){super.onInactive()coundManager.removeListener(listener)}companionobject{privatelateinitvarglobalData:GlobalLivedatafungetInstance():GlobalLivedata{globalData=if(::globalData.isInitialized)globalDataelseGlobalLivedata()returnglobalData}}}倒计时代码比较长只贴一部分,有兴趣可以去github查看完整代码privatevallisteners=mutableListOf()初始化{valcountDown=object:CountDownTimer(2000*1000,1000){overridefunonTick(millisUntilFinished:Long){remainSecond--callback("remaining:${remainSecond}seconds")}overridefunonFinish(){callback("倒计时结束")}}countDown.start()}/***循环回调消息*/privatefuncallback(msg:String){for(listenerinlisteners){listener.change(msg)}}FragmentA,FragmentB监听倒计时状态GlobalLivedata.getInstance().observe(viewLifecycleOwner,{t->inflate.findViewById(R.id.tv_fragmentA).text="fragmenta:${t}"})GlobalLivedata.getInstance().observe(viewLifecycleOwner,{t->inflate.findViewById(R.id.tv_fragmentB).text="fragmentb:${t}"})最终效果最终效果,当我们切换Fragments时,两个Fragments显示的秒数是一样的。事实上,即使我们立即启动一个新的活动来查看剩余的秒数也是一样的。有兴趣的可以下载git代码,自己尝试转换Livedata。map和switchMap这两个方法可以用于将现有的Livedata转换为新的LivedataTransformation.map。观察活动中视图模型中的数据更新。当Activity中的按钮被点击时,会调用viewmodel.sendData方法发送数据,然后将发送的数据转换为Activity。然后activity打印log显示,直接看代码:创建一个viewmodel,在model中创建一个LivedataclassTransMapViewModel:ViewModel(){funsendData(){userLivedata.value=User("李白",1200)//CopyuserLivedata}valuserLivedata=MutableLiveData()valmapLiveData=Transformations.map(userLivedata){"${it.name}:${it.age}"//这里可以返回任何类型的数据}}dataclassUser(varname:String,varage:Int)代码中mapLiveData是通过userLivedata转换得到的,所以当我们调用sendData方法更新userLivedata中的方法时,mapLiveData的回调也会触发观察mapLiveData中的活动点击按钮发送小数据mapViewModel.mapLiveData.observe(this,{logEE(it)tv_map.text=it})btn_map.setOnClickListener{mapViewModel.sendData()}Transformation.switchMap在这个例子中,我们实现了以下逻辑:观察活动中viewmodel中的数据更新,当点击viewmodel.sendDatw在活动中按下按钮时将被调用一个发送数据的方法,然后将发送的数据转换为activity,然后activity会打印日志显示viewmodel类中的代码SwitchMapViewModel:ViewModel(){funsendData(){userLivedata.value=SwitchUser("LiBai",1200)}privatevaluserLivedata=MutableLiveData()valmapLiveData=Transformations。switchMap(userLivedata){changeUser(it!!)}privatefunchangeUser(it:SwitchUser):LiveData{returnMutableLiveData("${it.name}杜甫知道的名字")}}dataclassSwitchUser(varname:String,varage:Int)调用部分代码model.mapLiveData.observe(this,{logEE(it)})btn_switchmap.setOnClickListener{model.sendData()}合并两个Livedata(MediatorLiveData)想象这样一个场景,你的app有评论列表功能,你可以点赞列表的内容,每次点赞都是异步错误,你的产品需求不希望用户点赞太多,比如一分钟点赞数不能超过10个,这种场景很适合使用Livedata的merge功能。这么复杂的场景我们就不模拟了。我们的例子做了这样一件事:有两个点击按钮一次就相当于点赞一次。当我们点击按钮十次时,界面上会显示一段文字,提醒用户数据已被点击十次。代码展示:1.model代码classMeditorLiveViewModel:ViewModel(){varcount=0//计数字段funsetData1(name:String){liveData1.value=name}funsetData2(age:Int){liveData2.value=age}privatevalliveData1=MutableLiveData()privatevalliveData2=MutableLiveData()valliveCombind=MediatorLiveData()init{liveCombind.addSource(liveData1){increase()}liveCombind.addSource(liveData2){增加()}}privatefunincrease(){count++if(count==10){liveCombind.value="安安安安卓,你已经点击了${count}次了,我不跟你玩了,停下来吧..."}}}model创建了三个Livedata,其中两个是livedata1和livedata2,分别对应其中两个按钮。还有一个liveCombind用来回调十多个调用的场景。init方法中的liveCombind.addSource调用,用于中间拦截livedata1和livedata2的数据更新,处理计数累加,是否回调liveCombind的函数。activity中的代码model.liveCombind.observe(this){logEE(it)tv_count.text=it}btn_livedata1.setOnClickListener{model.setData1("LiBai")}btn_livedata2.setOnClickListener{model.setData2(1000)}中observeForeverobserveForever方法也是注册Livedata监听的方法,表示即使页面被覆盖不活跃,仍然可以收到数据变化的回调。Livedata和协程使用emit方法引入依赖。有时您可能需要处理异步任务。任务处理完成后刷新ui。在这种情况下,可以使用Livedata。扩展程序实现本例中,我们实现如下逻辑:在viewmodel中阻塞4s,然后通知activity代码:引入依赖插件实现'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'到启用异步任务方法/***启用异步任务*/funstartAsyncWithSecond(second:Int):LiveData=liveData{delay(second*1000L)emit("倒计时结束")//用于触发datacallback}当我们调用startAsyncWithSecond方法时会立即返回一个Livedata对象供我们在activity中注册和监听livedata监听model.startAsyncWithSecond(3).observe(this){logEE(it)//数据会在模型中延迟3s后返回这里}效果说明使用emitSource的效果和MediatorLiveData的效果是等价的。本例中,我们实现如下效果:点击按钮启动一个3s的异步任务,然后通知activity打印log然后再次启动一个3s的异步任务,然后通知activity再次打印log代码:创建异步任务方法funstartAsyncEmitSource(second:Int)=liveData{delay(second*1000L)emit("${second}第二次阻塞完成,再阻塞三秒后通知")valemitSourceLivedata=MutableLiveData()emitSource(emitSourceLivedata)delay(second*1000L)emitSourceLivedata.value="AgainBlock${second}secondstocomplete"}活动注册监控model.startAsyncEmitSource(3).observe(this){logEE(it)}效果如果觉得我的回答还可以,请点赞、关注、收藏,如果觉得不好,请在评论中指正。