本文是对ViewModel + LiveData + Databinding架构的一些探讨。
- 关于Databinding :https://developer.android.com/topic/libraries/data-binding
- 关于LiveData:https://developer.android.com/topic/libraries/architecture/livedata
- 关于ViewModel:https://developer.android.com/topic/libraries/architecture/viewmodel
直接上代码:
ViewModel:
public class SplshViewModel extends BaseViewModel<SplashNavigator> {
MutableLiveData<PosterBean> data = new MutableLiveData();
PosterBean p = new PosterBean();
private DisposableSubscriber disposableSubscriber;
@Override
public void loadData() {
RetrofitManager.getInstance().createReq(SplashApi.class)
.getPoster()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseObserver<PosterBean>() {
@Override
public void onSuccees(PosterBean posterBean) {
if (posterBean.getCode() != 0) {
getNavigator().showMessage(posterBean.getMessage());
return;
}
p.setCode(posterBean.getCode());
p.setData(posterBean.getData());
p.setMessage(posterBean.getMessage());
data.setValue(p);
}
@Override
public void onFailure(String message) {
getNavigator().showMessage(message);
}
});
}
public LiveData<PosterBean> getData() {
return data;
}
public void shipOnClick(View view) {
getNavigator().openMainActivity();
}
public void posterOnClick(View view) {
}
public void startCount(int t) {
disposableSubscriber = new DisposableSubscriber<Long>() {
@Override
public void onNext(Long aLong) {
int time = (int) (t - aLong);
getNavigator().upoutime(time);
}
@Override
public void onError(Throwable t) {
System.out.println(t.toString());
}
@Override
public void onComplete() {
getNavigator().openMainActivity();
}
};
Flowable.interval(0, 1, TimeUnit.SECONDS, Schedulers.newThread())
.take(t)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(disposableSubscriber);
}
@Override
protected void onCleared() {
super.onCleared();
if (disposableSubscriber != null)
if (!disposableSubscriber.isDisposed()) {
disposableSubscriber.dispose();
disposableSubscriber = null;
}
}
}
Activity:
public class SplashActivity extends BaseActivity<ActivitySplashBinding, SplshViewModel> implements SplashNavigator {
private boolean qz = false;
private AlertDialog.Builder normalDialog;
private AlertDialog dialog;
@Override
protected SplshViewModel getViewModel() {
SplshViewModel splshViewModel = ViewModelProviders.of(this).get(SplshViewModel.class);
return splshViewModel;
}
@Override
protected int getLayoutResId() {
return R.layout.activity_splash;
}
@Override
protected void initView() {
mViewModel.setNavigator(this);
mViewModel.loadData();
mViewModel.getData().observe(this, posterBean -> {
mBinding.setViewModel(mViewModel);
});
}
@Override
protected String getLogTag() {
return "SplashActivity";
}
@Override
public void showMessage(String msg) {
showToas(msg);
}
@Override
public void finsh() {
finish();
}
@Override
public void openMainActivity() {
if (qz) return;
startActivity(new Intent(mContext, MainActivity.class));
finish();
}
@Override
public void loadImage(String url) {
mBinding.tvSkip.setVisibility(View.VISIBLE);
Glide.with(mContext).load(url).into(mBinding.ivPoster);
}
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.xueseng.activity.SplashActivity">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="com.xueseng.viewmodel.SplshViewModel" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
>
<ImageView
android:id="@+id/iv_poster"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_white"
android:scaleType="centerCrop"
android:onClick="@{viewModel.posterOnClick}"
android:src="@mipmap/lunchpage" />
<TextView
android:id="@+id/tv_skip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="20dp"
android:layout_marginBottom="40dp"
android:background="@drawable/shape_splah_taks"
android:paddingLeft="8dp"
android:paddingTop="3dp"
android:paddingRight="8dp"
android:paddingBottom="3dp"
android:onClick="@{viewModel.shipOnClick}"
android:text="跳过 3"
android:visibility="gone" />
</RelativeLayout>
</layout>
- 解释
SplshViewModel的loadData()加载数据,getData获取数据,然后activity通过 mViewModel.getData().observe()订阅,数据变化时回调,然后通过 DataBindingUtil.setContentView(this, getLayoutResId());获取到databinding。(这段代码我封装在baseActivity当中了),最后通过mBinding.setViewModel(mViewModel);将数据和databinding绑定,我这里绑定的是viewModel,因为,我点击事件方法写在ViewModel当中的。
- 问题
相信这段代码大家都能看懂,但是有一个问题,我想把业务相关的代码放在ViewModel中处理,比如,开屏页展示的广告,我需要判断广告类型,控制跳转具体的页面。我定义了一个SplashNavigator接口,Activity实现该接口,然后通过mViewModel.setNavigator(this); ViewModel持有SplashNavigator,这时候ViewMdel处理完数据,然后通过SplashNavigator提供的具体的方法,具体的去控制页面跳转。这只是一个简单的需求,项目中或许需要更复杂的处理完数据后和activity交互。但是官方文档中说,ViewModel中最好不要持有Activity或者Context的引用,那么我想在ViewModel中处理业务和数据,Activity仅仅只负责更新UI。此时我应该怎么做呢?
我知道大部分数据可以通过DataBinding来和View进行绑定,还可以双向绑定,那比如我要showDialog、showToas、这种时候该怎么做呢?
- 网上能找到的文章基本你抄我我超你,或者照着官方的几行代码写一小段,完全没有实际意义,希望有大神不吝赐教,共同探讨一下,感谢。
网友评论