本文会深入解析LiveData的原理及其应用

1、背景

之前的业务中有一个问题,我一个异步数据,供一个Activity使用,如果用强引用的callback,一是会造成内存泄漏,二是如果Activity destroy了,回调会有问题。另外一种方案是采用weakreference的callback,但这样一来就不能使用匿名内部类,使用起来不是很方便,所以研究一下能不能用LiveData来实现。

2、实现

首先是异步的DataLoader:

public class DataLoader {

    public Observable<UserInfoBean> getUserInfoQuickly(String name) {
        return Observable.just(name)
                .map(new Func1<String, UserInfoBean>() {
                    @Override
                    public UserInfoBean call(String s) {
                        int id = new Random().nextInt(1000);
                        return new UserInfoBean(s, id, id + "");
                    }
                })
                .delay(1, TimeUnit.SECONDS);
    }

    public Observable<UserInfoBean> getUserInfoSlowly(String name) {
        return Observable.just(name)
                .map(new Func1<String, UserInfoBean>() {
                    @Override
                    public UserInfoBean call(String s) {
                        int id = new Random().nextInt(1000);
                        return new UserInfoBean(s, id, id + "");
                    }
                })
                .delay(5, TimeUnit.SECONDS);
    }
}

使用LiveData的LiveDataLoader:

public class LiveDataLoader {

    private DataLoader loader = new DataLoader();
//    private MutableLiveData<UserInfoBean> userInfo = new MutableLiveData<>();

    public LiveData<UserInfoBean> getUserInfoQuickly(String name) {
        final MutableLiveData<UserInfoBean> userInfo = new MutableLiveData<>();
        loader.getUserInfoQuickly(name)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<UserInfoBean>() {
                    @Override
                    public void call(UserInfoBean userInfoBean) {
                        userInfo.setValue(userInfoBean);
                    }
                });
        return userInfo;
    }

    public LiveData<UserInfoBean> getUserInfoSlowly(String name) {
        final MutableLiveData<UserInfoBean> userInfo = new MutableLiveData<>();
        loader.getUserInfoSlowly(name)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<UserInfoBean>() {
                    @Override
                    public void call(UserInfoBean userInfoBean) {
                        userInfo.setValue(userInfoBean);
                    }
                });
        return userInfo;
    }
}

在Activity中使用:

public class ViewModelDemo2 extends AppCompatActivity {

    private ActivityViewModelDemo2Binding binding;
    private UserInfoViewModel viewModel;
    private LiveDataLoader liveDataLoader = new LiveDataLoader();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_view_model_demo2);
        viewModel = ViewModelProviders.of(this).get(UserInfoViewModel.class);
        binding.setUserinfo(viewModel);
        binding.setHandler(this);
        binding.setLifecycleOwner(this);
//        liveDataLoader = ViewModelProviders.of(this).get(LiveDataLoader.class);
    }

    public void doLoadUserInfo1() {
        liveDataLoader.getUserInfoQuickly(viewModel.editName.getValue())
                .observe(this, new Observer<UserInfoBean>() {
                    @Override
                    public void onChanged(@Nullable UserInfoBean userInfoBean) {
                        Toast.makeText(ViewModelDemo2.this, userInfoBean.toString(), Toast.LENGTH_SHORT).show();
                    }
                });
    }

    public void doLoadUserInfo2() {
        liveDataLoader.getUserInfoSlowly(viewModel.editName.getValue())
                .observe(this, new Observer<UserInfoBean>() {
                    @Override
                    public void onChanged(@Nullable UserInfoBean userInfoBean) {
                        Toast.makeText(ViewModelDemo2.this, userInfoBean.toString(), Toast.LENGTH_SHORT).show();
                    }
                });
    }
}

LiveDataLoader并没有继承ViewModel,关于LiveData是否需要结合ViewModel使用,官网文档中有这样一段描述:

Note: Make sure to store LiveData objects that update the UI in ViewModel objects, as opposed to an activity or fragment, for the following reasons:

  • To avoid bloated activities and fragments. Now these UI controllers are responsible for displaying data but not holding data state.

  • To decouple LiveData instances from specific activity or fragment instances and allow LiveData objects to survive configuration changes.

大概意思就是说LiveData要结合ViewModel使用

其实只要不是跟界面结合很紧,单独使用也是可以的,而且这样一来可以在使用时才注册回调,非常方便

LiveData可以理解成带生命周期的callback

3、深入分析LiveData的原理

LiveData调用observe的时候,会把Activity的实例和observer传进去:

首先用一个LifecycleBoundObserver把LifeCycleOwner和Observer包进去,放在一个类似map的容器里,这就是实现回调功能的基础

owner.getLifecycle().addObserver(wrapper);

这句代码会把之前那个wrapper放到LifeCycle里面去,这个LifeCycle是个啥:

实际调用的是SupportActivity的实现:

addObserver的具体实现:

这里也会把observer装进这个mObserverMap里面,这里会关系到后面当Activity destroy了,这些observer会remove掉

当LiveData调用setValue的时候:

会调dispatchingValue:

会遍历mObservers,然后调用considerNotify实现回调:

那么是怎么实现当Activity destroy的时候,remove掉相关的observer呢?

当Activity或者Fragment状态变化,比如destroy的时候,会调用LifecycleRegistry的moveToState

接着调用LifecycleRegistry.sync()

LifecycleRegistry.backwardPass()

ObserverWithState.dispatchEvent()

最后会调到关键的函数:LiveData.onStateChanged,就在这里把observer remove掉: