Android Jetpack 之 LiveData
简介:
LiveData 是一个有生命周期感知 & 可观察数据持有者类。
作用:
持久化的观察数据的更改和变化。
特点:
1、感知对应的Activity的生命周期,只有生命周期处于onStart、onResume时,LiveData处于活动状态,
才会把更新的数据通知至对应的Activity。
2、当生命周期处于onStop 或 onPause 时,不回调数据更新,直至处于onResume时才会回调。
3、当生命周期处于onDestroy 时,观察者会自动退出,防止内存泄漏。
个人理解:
我们工作中,大部分应用会从网络或数据库存取数据,并根据数据更新数据,为了避免ANR,主线程中不能存取数据。
而后台线程中无法更新界面,通常我们的做法是让后台线程将数据通过Handler传递给主线程。但是当我们
页面逻辑复杂时,使用Handler这种方式会变的尤为麻烦,为了简化界面更新的工作,Google就为我们提供了
LiveData组件。
用法:
当我们得到数据后,通过 postValue() 投递数据,其他线程通过 getValue() 得到数据。为了通知其他线程,
LiveData采用观察者模式,通过observe()方法,其他线程可以在数据更新后立即得到通知。
我们先来一个简单的例子看看怎么使用。
如果是低版本的项目的话需要添加依赖:
implementation "android.arch.lifecycle:livedata:1.1.1"
我的话项目版本比较高,不需要添加,livedata包含在android.arch.lifecycle中,插一句,Lifecycle 组件包括LifecycleOwner、LifecycleObserver。Lifecycle 组件是执行操作以响应另一个组件(Activity或者Fragment)的生命周期状态的更改。 Lifecycle 生成更易于组织、更轻量级,更易于维护的代码。
上代码,首先是我们的bean类:
public class Person extends BaseObservable {
private String name;
private String sex;
@Bindable
public String getName() {
return name;
}
@Bindable
public String getSex() {
return sex;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
}
接下来是我们简单的页面布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:layout_gravity="center"
/>
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请求"/>
</LinearLayout>
然后就是我们的页面代码:
public class LiveDataActivity extends AppCompatActivity {
private TextView tv;
private Button btn;
private MutableLiveData<Person> personLD = new MutableLiveData<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_livedata);
tv = findViewById(R.id.tv);
btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//模拟网络请求
try {
Thread.sleep(3000);
Person person = new Person();
person.setName("白展堂");
person.setSex("男");
personLD.postValue(person);//设置数据
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
personLD.observe(this, new Observer<Person>() {//通过observe监听数据的变化
@Override
public void onChanged(@Nullable Person person) {
tv.setText("name:"+person.getName() +" sex: "+ person.getSex());//数据变化时更新页面
}
});
}
}
注:MutableLiveData 是 LiveData的一个实现类,它的直接父类是LiveData。
我们可以看到,observe()方法有两个参数,第一个参数的类型是LifecycleOwner,加入LifecycleOwner的目的是自动管理Activity生命周期。第二个参数是观察者。
到这里数据就可以正常显示了。
当我这里点击请求按钮的时候,马上退到桌面后台,即页面不可见的时候,虽然 postValue() 方法已执行,但是当页面不可见时,observer里面的 onChanged()是没有执行的,只有当我们重新打开这页面的时候,这个更新数据的方法才会执行。我们可以接着往下看。
实际上,LiveData的数据传递也是通过Handler传递的,在postValue方法的源码可以看到,,LiveData调用ArchTaskExecutor.postToMainThread(),将一个Runnable对象传递给主线程。这个Runnable对象调用setValue()对数据进行更新。当我们更新数据的时候,LiveData第一步是将版本号加1,第二步是遍历观察者。如果观察者处于活跃状态(Lifecycle.State是STARTED或RESUMED),并且观察者的版本号小于LiveData,LiveData会调用观察者的onChanged()方法进行通知。这个就是我们上面问题的原因。
当观察者的生命周期不是STARTED或RESUMED时,数据更新不会进行通知。它的实现方法是在我们调用observe()方法时,
我们第一个参数是LifecycleOwner,第二个参数是Observer。LiveData内部建立了一个LifecyleBoundObserver对象,它将我们传的参数绑定到了一起,用来接收Lifecycle的生命周期更新和LiveData的数据更新,LifecyleBoundObserver是LiveData的内部类,持有LiveData的引用,当生命周期发生变化时,LifecyleBoundObserver会调用LiveData的dispatchingValue()方法,获取最新数据进行更新。
日常工作中,我们使用LiveData通常是配合其他框架一起使用,一个是Room,一个是ViewModel,这两个都是Android Jetpack生态下的框架。
Room是Jetpack提供的SQLite 工具,它读取数据的方法都是阻塞的,要在后台子线程执行,所以非常适合与LiveData配合使用,据我了解Room定义的Dao支持返回LiveData(没用过),当我们查询数据库返回后,可以对界面进行更新。
ViewModel可以用来管理Activity或Fragment中的各个LiveData对象。可以把ViewModel看成是LiveData的集合。
ViewModel的作用是可以和Activity或Fragment绑定在一起,并且在配置改变引起的Activity/Fragment销毁时,ViewModel仍然可以持有状态。
今天就写到这里吧。共勉
上一篇: EventBus详解