JetPack架构---LiveData的使用与示例
Posted 战国剑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JetPack架构---LiveData的使用与示例相关的知识,希望对你有一定的参考价值。
本文介绍:LiveData的单独使用、LiveData与ViewModel结合使用、LiveData的复杂使用
一、LiveData的单独使用
以一个整型数据为例。将该整型数据用MutableLiveData包装。
在Activity中,监听count的变化:每次点击按钮,会生成随机数,并Toast表现。
public class LiveDataActivity extends AppCompatActivity
//定义一个MutableLiveData包装的Integer型数据count
private MutableLiveData<Integer> count = new MutableLiveData<>();
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_data);
//监听count的变化
count.observe(this, new Observer<Integer>()
@Override
public void onChanged(Integer integer)
//展示数据的变化
Toast.makeText(LiveDataActivity.this, String.valueOf(integer), Toast.LENGTH_SHORT).show();
);
findViewById(R.id.liveDataOnlyTest).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//驱动数据变化
count.setValue(new Random().nextInt());
);
该场景也可以扩展为:监听全局变量的数据变化,如Application中定义的变量等
二、LiveData结合ViewModel使用
ViewModel作为页面数据的存储空间。给相应的页面定义相应的ViewModel,管理该页面的所有数据。
2-0:定义一个ViewModel
public class MainViewModel extends ViewModel
private MutableLiveData<Integer> count = new MutableLiveData<>();
public MutableLiveData<Integer> getCount()
return count;
2-1:在页面上使用该ViewModel
页面上的ViewModel数据监听
//获取ViewModel
mainViewModel = new ViewModelProvider(this).get(MainViewModel.class);
//监听ViewModel中的count数据变化
mainViewModel.getCount().observe(this, new Observer<Integer>()
@Override
public void onChanged(Integer integer)
Toast.makeText(LiveDataActivity.this, "ViewModel+LiveData示例数据变化:" + integer, Toast.LENGTH_SHORT).show();
);
......
//驱动数据变化
findViewById(R.id.liveDataWithViewModel).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
mainViewModel.getCount().setValue(new Random().nextInt());
);
三、LiveData的使用进阶
3-0:LiveData数据转型---map
用于将该LiveData中的数据做一次过滤或者转变,生成一个新的LiveData。以一个Person类作为此次例子,该类含有name与age两个属性。将LiveData<Person>用Map转换后,只输出LiveData<String>。
//类定义
public class Person
public String name;
public int age;
//ViewModel定义
public class PersonViewModel extends ViewModel
private MutableLiveData<Person> person = new MutableLiveData<>();
public MutableLiveData<Person> getPerson()
return person;
------------以下为页面数据-----------
//ViewModel获取
personViewModel = new ViewModelProvider(this).get(PersonViewModel.class);
//数据转换的规则定义:将Person类变为只返回该类中的name
LiveData<String> map = Transformations.map(personViewModel.getPerson(), new Function<Person, String>()
@Override
public String apply(Person input)
return input.name;
);
//监听数据变化
map.observe(this, new Observer<String>()
@Override
public void onChanged(String s)
Toast.makeText(LiveDataActivity.this, "Person过滤转型后得到的名字:" + s, Toast.LENGTH_SHORT).show();
);
//驱动数据变化
findViewById(R.id.liveDataWithViewModelWhemMap).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Person person = new Person();
person.name = "晓明";
person.age = 18;
personViewModel.getPerson().setValue(person);
);
3-1:LiveData的数据转型---switchMap
//ViewModel定义
personViewModel = new ViewModelProvider(this).get(PersonViewModel.class);
//switchMap转换,与map不同的是,该方法的apply需要返回一个新的LiveData格式的数据。
LiveData<String> stringLiveData = Transformations.switchMap(personViewModel.getPerson(), new Function<Person, LiveData<String>>()
@Override
public LiveData<String> apply(Person input)
MutableLiveData test = new MutableLiveData<>();
test.setValue(input.name);
return test;
);
//数据变化监听
stringLiveData.observe(this, new Observer<String>()
@Override
public void onChanged(String s)
Toast.makeText(LiveDataActivity.this, "Person经SwitchMap转型后得到的名字:" + s, Toast.LENGTH_SHORT).show();
);
//驱动数据变化
findViewById(R.id.liveDataWithViewModelWhemSwitchMap).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Person person = new Person();
person.name = "晓红";
person.age = 18;
personViewModel.getPerson().setValue(person);
);
switchMap方法中,apply返回的是一个LiveData类型的数据。这主要是在这样的场景中使用的:ViewModel中定义的LiveData,命名为A。A的数据不是在ViewModel中直接组装的,而是要通过调用其他方法获取的。此时,用switchMap将获取到的LiveData,赋值给 A。
常见的场景有:ViewModel中调用方法从网络或者数据库获取数据。
3-2:MediatorLiveData的使用
MediatorLiveData是LiveData的子类,可以合并多个LiveData数据源,当任意一个数据源数据发生变化,MediatorLiveData的监听都将起效。
//source1与source2作为两个数据源
private MutableLiveData<Integer> source1 = new MutableLiveData<>();
private MutableLiveData<Integer> source2 = new MutableLiveData<>();
//source整合两个数据源
public MediatorLiveData<Integer> source = new MediatorLiveData<>();
//统一的监听回调
private Observer<Integer> observer = new Observer<Integer>()
@Override
public void onChanged(Integer s)
source.setValue(s);
;
-----------------页面-----------------
//添加数据源
source.addSource(source1,observer);
source.addSource(source2,observer);
source.observe(this, new Observer<Integer>()
@Override
public void onChanged(Integer integer)
Toast.makeText(LiveDataActivity.this, "--->"+integer, Toast.LENGTH_SHORT).show();
);
----------------驱动数据--------------
//无论是source1还是source2的数据变化,都将触发回调
source1.postValue(1);
source2.setValue(2);
MediatorLiveData可用于网络与本地数据库同时存在,有两个数据源时,无论二者中,哪部分数据发生变化,都能起效。
3-3:LiveData的封装---LiveDataBus
应用中,存在多个页面之间,都会共用一个或者一组数据的情况。
1、如ActivityA,ActivityB都会同时监听某个数据的变化,需要根据这个数据的变化,做某些操作。
2、组件之间同时监听同一数据的变化。
3、组件间的通讯。
以上几种情况都可以通过封装LiveData,实现一个LiveData的通讯框架来实现。命名这个框架为LiveDataBus。
这个框架同时也会解决前文:JetPack架构---LiveData特性、原理 中提到的“为什么LiveData会带有粘性特制”,把该特性屏蔽,避免额外问题。
LiveDataBus的实现只需一个类,如下(部分引用自网络),该类简单的说,就是一个Map,用于存储多个LiveData。
public class LiveDataBus
private static volatile LiveDataBus INSTANCE;
private final Map<String, MutableLiveData<Object>> bus;
private LiveDataBus()
bus = new HashMap<>();
public static LiveDataBus get()
if(INSTANCE == null)
synchronized (LiveDataBus.class)
INSTANCE = new LiveDataBus();
return INSTANCE;
//此处type用于后续可能的observe或者post/set value
//此处key用于生成或者获取,该key对应的LiveData
public synchronized <T> MutableLiveData<T> with(String key,Class<T> type)
if (!bus.containsKey(key))
bus.put(key,new BusMutableLiveData<>());
return (MutableLiveData<T>) bus.get(key);
//hook会反射方式复写 observer中version的控制
public static class BusMutableLiveData<T> extends MutableLiveData<T>
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
super.observe(owner, observer);
try
hook(observer);
catch (Exception e)
e.printStackTrace();
/**
* 反射技术 使observer.mLastVersion = mVersion
*
* @param observer ob
*/
private void hook(Observer<? super T> observer) throws Exception
//根据源码 如果使observer.mLastVersion = mVersion; 就不会走 回调OnChange方法了,所以就算注册
//也不会收到消息
//首先获取liveData的class
Class<LiveData> classLiveData = LiveData.class;
//通过反射获取该类里mObserver属性对象
Field fieldObservers = classLiveData.getDeclaredField("mObservers");
//设置属性可以被访问
fieldObservers.setAccessible(true);
//获取的对象是this里这个对象值,他的值是一个map集合
Object objectObservers = fieldObservers.get(this);
//获取map对象的类型
Class<?> classObservers = objectObservers.getClass();
//获取map对象中所有的get方法
Method methodGet = classObservers.getDeclaredMethod("get", Object.class);
//设置get方法可以被访问
methodGet.setAccessible(true);
//执行该get方法,传入objectObservers对象,然后传入observer作为key的值
Object objectWrapperEntry = methodGet.invoke(objectObservers, observer);
//定义一个空的object对象
Object objectWrapper = null;
//判断objectWrapperEntry是否为Map.Entry类型
if (objectWrapperEntry instanceof Map.Entry)
objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();
if (objectWrapper == null)
throw new NullPointerException("Wrapper can not be null!");
//如果不是空 就得到该object的父类
Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
//通过他的父类的class对象,获取mLastVersion字段
Field fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion");
fieldLastVersion.setAccessible(true);
Field fieldVersion = classLiveData.getDeclaredField("mVersion");
fieldVersion.setAccessible(true);
Object objectVersion = fieldVersion.get(this);
//把mVersion 字段的属性值设置给mLastVersion
fieldLastVersion.set(objectWrapper, objectVersion);
LiveDataBus的使用方式很简便:
//LiveData监听,该LiveData的识别码是Define.STR_KEY,该值随意定义
LiveDataBus.get().with(Define.STR_KEY, String.class).observe(Main2Activity.this, new Observer<String>()
@Override
public void onChanged(String info)
Log.e(TAG, "onChanged: " + info);
);
//LiveData,驱动数据变化
LiveDataBus.get().with(Define.INFO_KEY, String.class).postValue(info);
LiveData从入门用法、与ViewModel结合,到后续的转换、封装。基本囊括了目前LiveData的使用方式。如需扩展等,仍然可以根据LiveData的特性,自定义相应的LiveData。
以上是关于JetPack架构---LiveData的使用与示例的主要内容,如果未能解决你的问题,请参考以下文章
Android Jetpack架构组件——LiveData使用篇
Android Jetpack架构组件——LiveData使用篇
Android Jetpack架构组件一文带你了解LiveData(使用篇)
Android jetpack架构组件LiveData实战与源码解析