一.实时数据LiveData
在上一节中,我们学习了ViewModel,了解到ViewModel的主要作用是存放页面所需要的各种数据。我们在示例代码中定义了接口,当数据发生变化的时候,采用接口的方式实现对页面的通知。但是这种方式是有缺陷的,当要存储的数据非常多的时候,就要定义大量的接口,代码会显得十分冗余,为此JetPack提供了LiveData组件。LiveData是一个可被观察的数据容器类,具体来说,可以将LiveData理解为一个数据的容器,它将数据包装起来,使数据成为被观察者,当数据发生变化的时候,观察者能够获得通知。我们不需要自己去实现观察者模式,LiveData内部已经默认实现好了。
下面我们用LiveData替代上一节定义的接口,完成ViewModel和页面之间的通信。
二.LiveData和ViewModel的关系
ViewModel用于存储页面所需要的数据,不仅如此,我们还可以在其中放一些与数据相关的业务逻辑。例如,可以在ViewModel中进行数据的获取和加工等操作。因此,ViewModel中的数据可能随着业务的变化而发生变化。对页面来说,它并不关心ViewModel的业务逻辑,它只关心需要展示的数据是什么,并且希望在数据发生变化的时候,能及时得到通知并做出更新。LiveData的作用就是,在ViewModel中的数据发生变化的时候通知页面更新。因此,LiveData通常被放在ViewModel中使用,用于包装ViewModel中那些需要被外界观察的数据。
三.LiveData的基本使用方法
LiveData是一个抽象类,不能直接使用,通常使用的是他的直接子类MutableLiveData。下面我们改造上一节的代码,如下所示:
public class TimerViewModel extends ViewModel { private MutableLiveData<Integer> currentSecond; private Timer timer; private Integer second=0; @Override protected void onCleared() { super.onCleared(); timer.cancel(); } public void startTiming(){ if(timer==null){ timer=new Timer(); TimerTask timerTask=new TimerTask() { @Override public void run() { second++; currentSecond.postValue(second); } }; timer.schedule(timerTask,1000,1000); } } public LiveData<Integer> getCurrentSecond(){ if(currentSecond==null){ currentSecond=new MutableLiveData<>(); } return currentSecond; } }
public class MainActivity extends AppCompatActivity { private TextView tv_display; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); iniComponent(); } private void iniComponent() { tv_display=findViewById(R.id.tv_display); TimerViewModel timerViewModel=new ViewModelProvider(this).get(TimerViewModel.class); MutableLiveData<Integer> liveData= (MutableLiveData<Integer>) timerViewModel.getCurrentSecond(); liveData.observe(this, new Observer<Integer>() { @Override public void onChanged(Integer second) { tv_display.setText(second+""); } }); timerViewModel.startTiming(); } }
在页面中,通过LiveData.observe()方法对LiveData所包装的数据进行观察,当该数据发生变化的时候,就可以得到更新后的数据,并在onChanged()方法中做出处理。当我们需要修改LiveData中的数据时,可以通过LiveData.postValue()和LiveData.setValue()方法来完成。postValue()方法用在非UI线程,setValue()方法用在UI线程中。
四.LiveData的原理
为了更好地理解LiveData,我们可以深入LiveData.observe()方法的源码一探究竟。
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles"); } if (existing != null) { return; } owner.getLifecycle().addObserver(wrapper); }
从源码可以看到,observe方法接收的第一个参数是LifecycleOwner对象,在本例中是Activity,第二个参数是一个Observer对象。从源码中可以发现,当页面的状态为Destroy时,直接return了,否则将observer添加为页面的观察者。也就是说,只有页面处于激活状态时,页面才可以收到来自LiveData的通知,若页面处于destroy状态,那么LiveData会自动清除与页面的关联,从而避免可能引起的内存泄漏问题。
五.LiveData.observeForever()方法
LiveData还提供了一个名为observeForever()的方法,它的用法和observe方法相似,主要的区别在于,当LiveData中的数据发生变化时,无论页面处于什么状态,observeForever()方法都可以收到通知。因此,在用完之后,一定要记得调用removeObserver()方法来停止对LiveData的观察,否则LiveData会一直处于激活状态,Activity则永远不会被系统自动回收,这就造成了内存泄漏。
- LiveData160 livedata android jetpack bottomnavigationview viewmode livedata android transform livedata repository viewmodel livedata room viewmodel livedata fragment viewmodel livedata livedata android jetpack数据 transformations livedata android 架构 组件livedata android fragment viewmodel livedata activity