之前的业务中有一个问题,我一个异步数据,供一个Activity使用,如果用强引用的callback,一是会造成内存泄漏,二是如果Activity destroy了,回调会有问题。另外一种方案是采用weakreference的callback,但这样一来就不能使用匿名内部类,使用起来不是很方便,所以研究一下能不能用LiveData来实现。
首先是异步的DataLoader:
public class DataLoader {
public Observable getUserInfoQuickly(String name) {
return Observable.just(name)
.map(new Func1() {
@Override
public UserInfoBean call(String s) {
int id = new Random().nextInt(1000);
return new UserInfoBean(s, id, id + "");
}
})
.delay(1, TimeUnit.SECONDS);
}
public Observable getUserInfoSlowly(String name) {
return Observable.just(name)
.map(new Func1() {
@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 userInfo = new MutableLiveData<>();
public LiveData getUserInfoQuickly(String name) {
final MutableLiveData userInfo = new MutableLiveData<>();
loader.getUserInfoQuickly(name)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1() {
@Override
public void call(UserInfoBean userInfoBean) {
userInfo.setValue(userInfoBean);
}
});
return userInfo;
}
public LiveData getUserInfoSlowly(String name) {
final MutableLiveData userInfo = new MutableLiveData<>();
loader.getUserInfoSlowly(name)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1() {
@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() {
@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() {
@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
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掉: