欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android-ViewModel和LiveData使用详解

程序员文章站 2023-08-25 23:15:52
viewmodel类的设计目的是以一种关注生命周期的方式存储和管理与ui相关的数据。例如:activity在配置发生改变时(屏幕旋转),activity就会重新创建,oncreate()方法也会重新调...

viewmodel类的设计目的是以一种关注生命周期的方式存储和管理与ui相关的数据。

例如:activity在配置发生改变时(屏幕旋转),activity就会重新创建,oncreate()方法也会重新调用。我们可以在onsaveinstancestate()方法中保存数据,并从oncreate()方法中通过bundle恢复数据,但这种方法只适用于可以对其进行序列化的少量数据,而不适用于潜在的大量数据。使用viewmodel的话viewmodel会自动保留之前的数据并给新的activity或fragment使用。直到当前activity被系统销毁时,framework会调用viewmodel的oncleared()方法,我们可以在oncleared()方法中做一些资源清理操作。

livedata是一个可观察的数据持有者类。与常见的观察者不同,livedata是有生命周期感知的。这意味着它尊重其他应用程序组件的生命周期,比如activity、fragment或service。这种感知确保livedata只更新处于生命周期状态内的应用程序组件。

livedata是由observer类表示的观察者视为处于活动状态,如果其生命周期处于started或resumed状态。livedata会将观察者视为活动状态,并通知其数据的变化。livedata未注册的观察对象以及非活动观察者是不会收到有关更新的通知。

livedata的优点:

确保ui界面的数据状态

livedata遵循观察者模式。livedata在生命周期状态更改时通知observer对象,更新这些observer对象中的ui。观察者可以在每次应用程序数据更改时更新ui,而不是每次发生更改时更新ui。

没有内存泄漏

当观察者被绑定他们对应的lifecycle以后,当页面销毁时他们会自动被移除,不会导致内存溢出。

不会因为activity的不可见导致crash

当activity不可见时,即使有数据变化,livedata也不会通知观察者。因为此时观察者的lifecyele并不处于started或者resumed状态。

配置的改变

当前activity配置改变(如屏幕方向),导致重新从oncreate走一遍,这时观察者们会立刻收到配置变化前的最新数据。

不用再人为的处理生命周期

activity或者fragment只要在需要观察数据的时候观察数据即可,不需要理会生命周期变化了。这一切都交给livedata来自动管理。

添加viewmodel和livedata库的依赖

//build.gradle文件中
allprojects {
 repositories {
  google()
  jcenter()
 }
}
//app/build.gradle文件中
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0-alpha1'

定义viewmodel和创建livedata

package io.dcloud.h56580e2e.viewmodellivedata;

import android.app.application;

import androidx.annotation.nonnull;
import androidx.lifecycle.androidviewmodel;
import androidx.lifecycle.mutablelivedata;
import androidx.lifecycle.viewmodel;
/**
 * viewmodel 主要解决的是fragment的参数传递问题
 * viewmode和对象实例绑定,也就是说viewmodel不会由于configurationchange而改变。比如:在你的手机进行翻转时,activity会重新走生命周期。
 * 那么如果在activity中保存的数据,就很有可能,被复写,重置或者丢失。但是如果我们将activity当作view组件的话,那么我们的关键属性就会自然而然的存放在viewmodel中。
 * 这时候如果acitivty的configrationchange调用的话,由于activity对象并没有被重建,还是之前的对象,那么我们所取到的viewmodel也不会发生变化
 */

/**
 * 定义viewmodel和创建livedata
 * viewmodel是以关联生命周期的方式来存储和管理ui相关的数据的类,即使configuration发生改变(比如旋转屏幕),数据仍然可以存在不会销毁(使用viewmodel就继承 androidviewmodel/viewmodel )
 * androidviewmodel(viewmodel的子类):需要使用到context对象时继承它 否则继承 viewmodel
 *
 * livedata是一个可观察的数据持有者类
 * viewmodel 与 livedata相互配合使用
 */
public class domemodel extends viewmodel {
 //创建livedata(可以创建多个不同类型的 livedata..)
 private mutablelivedata<domeinfo> mdomelivedata;

 /**
  * 改变 livedata 中的数据
  * 使用 setvalue()
  * @param phone_str
  * @param pwd_str
  * setvalue()要在主线程中调用
  */
 public void setdomeinfo(string phone_str,string pwd_str){
  mdomelivedata.setvalue(new domeinfo(phone_str,pwd_str));
 }

 /**
  * 改变 livedata 中的数据
  * 使用 postvalue()
  * postvalue()既可在主线程也可在子线程中调用
  */
 public void postdomeinfo(string phone_str,string pwd_str){
  mdomelivedata.postvalue(new domeinfo(phone_str,pwd_str));
 }

 /**
  *
  * @return
  */
 public mutablelivedata<domeinfo> getmdomelivedata(){
  if(mdomelivedata == null){
   mdomelivedata = new mutablelivedata<>();
  }
  return mdomelivedata;
 }
 // 当myactivity被销毁时,framework会调用viewmodel的oncleared()
 @override
 protected void oncleared() {
  super.oncleared();
 }
}

使用(演示在 activity中与fragment中和fragment与fragment相互通信)

在activity中:

package io.dcloud.h56580e2e.viewmodellivedata;

import androidx.appcompat.app.appcompatactivity;
import androidx.lifecycle.observer;
import androidx.lifecycle.viewmodelproviders;
import butterknife.bindview;
import butterknife.butterknife;
import io.dcloud.h56580e2e.r;
import io.reactivex.functions.consumer;
import android.os.bundle;
import android.widget.button;
import android.widget.textview;

import com.jakewharton.rxbinding3.view.rxview;

import java.util.concurrent.timeunit;

public class domeactivity extends appcompatactivity {
 @bindview(r.id.button)
 button addbut;
 @bindview(r.id.textview3)
 textview showdata_text;
 //viewmodel 对象
 private domemodel domemodel;
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_dome);
  butterknife.bind(this);

  //添加 fragment视图
  getsupportfragmentmanager().begintransaction().replace(r.id.framelayout1,new onefragment()).commit();
  getsupportfragmentmanager().begintransaction().replace(r.id.framelayout2,new twofragment()).commit();
  //初始化 viewmodel
  domemodel = viewmodelproviders.of(this).get(domemodel.class);
  //button按钮点击事件
  rxview.clicks(addbut).throttlefirst(2, timeunit.seconds)
    .subscribe(new consumer<object>() {
     @override
     public void accept(object unit) throws exception {
      //使用 postvalue()方法更新一条数据
      domemodel.postdomeinfo("13233253173","11111111");
     }
    });
  //获取 上面更新的数据
  domemodel.getmdomelivedata().observe(this, new observer<domeinfo>() {
   @override
   public void onchanged(domeinfo domeinfo) {
    showdata_text.settext("账号:"+domeinfo.getphone_str()+"密码:"+domeinfo.getpwd_str());
   }
  });
 }
}

fragment 1:

package io.dcloud.h56580e2e.viewmodellivedata;

import androidx.lifecycle.observer;
import androidx.lifecycle.viewmodelproviders;

import android.os.bundle;

import androidx.annotation.nonnull;
import androidx.annotation.nullable;
import androidx.fragment.app.fragment;

import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
import android.widget.button;
import android.widget.textview;

import com.jakewharton.rxbinding3.view.rxview;

import java.util.concurrent.timeunit;

import butterknife.bindview;
import butterknife.butterknife;
import butterknife.unbinder;
import io.dcloud.h56580e2e.r;
import io.reactivex.functions.consumer;


public class onefragment extends fragment {
 //butterknife对象
 private unbinder unbinder;
 //创建 viewmodel 对象
 private domemodel domemodel;
 @bindview(r.id.textview)
 textview show_textview;
 @bindview(r.id.button2)
 button update_but;
 public onefragment() {
 }

 @override
 public void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
 }

 @override
 public view oncreateview(@nonnull layoutinflater inflater, @nullable viewgroup container,
        @nullable bundle savedinstancestate) {
  view view= inflater.inflate(r.layout.one_fragment, container, false);
  unbinder=butterknife.bind(this,view);
  return view;
 }

 /*onviewcreated是在oncreateview后被触发的事件*/
 @override
 public void onviewcreated(@nonnull view view, @nullable bundle savedinstancestate) {
  super.onviewcreated(view, savedinstancestate);
 }

 @override
 public void onactivitycreated(@nullable bundle savedinstancestate) {
  super.onactivitycreated(savedinstancestate);
  domemodel=viewmodelproviders.of(getactivity()).get(domemodel.class);
  //在 onefragment中更新数据
  rxview.clicks(update_but).throttlefirst(2,timeunit.seconds)
    .subscribe(new consumer<object>() {
     @override
     public void accept(object unit) throws exception {
      domemodel.postdomeinfo("fragement1323325317","123456");
     }
    });

  // 获取更新的数据(结合 rxjava2 操作符)
  domemodel.getmdomelivedata().observe(this, new observer<domeinfo>() {
   @override
   public void onchanged(domeinfo domeinfo) {
    show_textview.settext("账号:"+domeinfo.getphone_str()+"密码:"+domeinfo.getpwd_str());
   }
  });
 }

 @override
 public void ondestroyview() {
  super.ondestroyview();
  //fragment销毁的时候解绑 butterknife
  unbinder.unbind();
 }
}

fragment 2:

package io.dcloud.h56580e2e.viewmodellivedata;

import android.content.context;
import android.os.bundle;

import androidx.annotation.nullable;
import androidx.fragment.app.fragment;

import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
import android.widget.button;
import android.widget.textview;

import com.jakewharton.rxbinding3.view.rxview;

import java.util.concurrent.timeunit;

import androidx.lifecycle.observer;
import androidx.lifecycle.viewmodelproviders;
import butterknife.bindview;
import butterknife.butterknife;
import butterknife.unbinder;
import io.dcloud.h56580e2e.r;
import io.reactivex.functions.consumer;

/**
 * a simple {@link fragment} subclass.
 * activities that contain this fragment must implement the
 * create an instance of this fragment.
 */
public class twofragment extends fragment {
 @bindview(r.id.textview5)
 textview show_textview;
 @bindview(r.id.button3)
 button button;
 private domemodel domemodel;
 private unbinder unbinder;

 public twofragment() {
  // required empty public constructor
 }



 @override
 public void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
 }

 @override
 public view oncreateview(layoutinflater inflater, viewgroup container,
        bundle savedinstancestate) {
  // inflate the layout for this fragment
  view view= inflater.inflate(r.layout.fragment_two, container, false);
  unbinder=butterknife.bind(this,view);
  return view;
 }

 @override
 public void onactivitycreated(@nullable bundle savedinstancestate) {
  super.onactivitycreated(savedinstancestate);
  domemodel = viewmodelproviders.of(getactivity()).get(domemodel.class);
  rxview.clicks(button).throttlefirst(2,timeunit.seconds)
    .subscribe(new consumer<object>() {
     @override
     public void accept(object unit) throws exception {
      domemodel.postdomeinfo("fragement2-1323325317","123456");
     }
    });
  // 获取更新的数据(结合 rxjava2 操作符)
  domemodel.getmdomelivedata().observe(this, new observer<domeinfo>() {
   @override
   public void onchanged(domeinfo domeinfo) {
    show_textview.settext("账号:"+domeinfo.getphone_str()+"密码:"+domeinfo.getpwd_str());
   }
  });
 }

 @override
 public void onattach(context context) {
  super.onattach(context);
 }

 @override
 public void ondetach() {
  super.ondetach();
 }

 @override
 public void ondestroyview() {
  super.ondestroyview();
  //fragment销毁的时候解绑 butterknife
  unbinder.unbind();
 }
}

dome实体类:

package io.dcloud.h56580e2e.viewmodellivedata;

/**
 * dome实体类
 */
public class domeinfo {
 private string phone_str;
 private string pwd_str;

 public domeinfo(string phone_str, string pwd_str) {
  this.phone_str = phone_str;
  this.pwd_str = pwd_str;
 }

 public domeinfo() {
 }

 public string getphone_str() {
  return phone_str;
 }

 public void setphone_str(string phone_str) {
  this.phone_str = phone_str;
 }

 public string getpwd_str() {
  return pwd_str;
 }

 public void setpwd_str(string pwd_str) {
  this.pwd_str = pwd_str;
 }
}

以上这篇android-viewmodel和livedata使用详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。