閑話不多少往湿,還是老套路妖异,處理一個(gè)登陸的業(yè)務(wù)。詳細(xì)的介紹MVVM我就不多說(shuō)了领追,網(wǎng)上一大把他膳,畢竟吹水還是我的弱項(xiàng)。
主要實(shí)現(xiàn)的功能有兩個(gè)輸入框绒窑,一個(gè)登陸按鈕棕孙,兩個(gè)TextView顯示登陸結(jié)果。
秀一把我的LoginActivity
@BindLayout(R.layout.activity_login)
public class LoginActivity extends BaseActivity<ILoginViewModel, LoginActivityBriefnessor> implements ILoginView {
@Override
protected ILoginViewModel createViewModel(LoginActivityBriefnessor briefnessor) {
return new LoginViewModel(this, briefnessor);
}
}
是不是超級(jí)簡(jiǎn)潔些膨,點(diǎn)擊事件呢蟀俊?怎么不見(jiàn)了,再看一看ViewModel
public class LoginViewModel extends BaseViewModel<ILoginView, ILoginModel, LoginActivityBriefnessor> implements ILoginViewModel {
public LoginViewModel(ILoginView view, LoginActivityBriefnessor briefnessor) {
super(view, briefnessor);
}
@Override
protected ILoginModel createModel() {
return new LoginModel(this);
}
@Override
public void onLoginClick(String account, String pswd) {
if (account.length() < 3) {
Toast.makeText(context(), "賬號(hào)不正確", Toast.LENGTH_SHORT).show();
return;
}
if (pswd.length() < 3) {
Toast.makeText(context(), "密碼不正確", Toast.LENGTH_SHORT).show();
return;
}
model.login(account, pswd);
}
@Override
public void callbackLogin(LoginResult result) {
briefnessor.setResult(result);
}
}
ViewModel制作了登陸的數(shù)據(jù)驗(yàn)證订雾,以及登陸回調(diào)的實(shí)現(xiàn)肢预,model層完成模擬了登陸。
整個(gè)登陸的業(yè)務(wù)流程Activity并沒(méi)有參與洼哎,在這其中就不得不提一個(gè)關(guān)鍵的中間件Briefness烫映,它連接了View層與Model層,幫我們實(shí)現(xiàn)了數(shù)據(jù)綁定谱净,以及事件傳遞窑邦。
我們先看一看布局是如何實(shí)現(xiàn)的
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:imports="com.hacknife.demo.bean.LoginResult,result"a
app:viewModel="com.hacknife.demo.mvvm.viewmodel.ILoginViewModel"
tools:ignore="MissingPrefix">
<EditText
android:id="@+id/et_account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="40dp"
android:layout_marginVertical="10dp"
android:hint="賬號(hào)" />
<EditText
android:id="@+id/et_pswd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="40dp"
android:layout_marginVertical="10dp"
android:hint="密碼" />
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginHorizontal="40dp"
android:layout_marginVertical="10dp"
android:text="登陸"
app:transfer="onLoginClick($et_account$,$et_pswd$)" />
<LinearLayout style="@style/text_parent" android:layout_marginHorizontal="40dp">
<TextView
style="@style/text_childer"
android:text="返回碼" />
<TextView
android:id="@+id/tv_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:bind="$result.code$" />
</LinearLayout>
<LinearLayout style="@style/text_parent" android:layout_marginHorizontal="40dp">
<TextView
style="@style/text_childer"
android:text="結(jié)果:" />
<TextView
android:id="@+id/tv_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:bind="$result.msg$" />
</LinearLayout>
</LinearLayout>
布局中,根布局綁定了ViewModel壕探,以及用于展示登陸結(jié)果的數(shù)據(jù)源冈钦。登陸按鈕傳遞單擊登陸事件,剩下的兩個(gè)textView綁定相應(yīng)的字段李请。
同時(shí)在對(duì)應(yīng)的Activity上綁定相應(yīng)的布局文件瞧筛,Briefness就能暫時(shí)他強(qiáng)大的功能了,它會(huì)自動(dòng)生成[類(lèi)名+Briefnessor]的類(lèi)导盅。
public class LoginActivityBriefnessor implements Briefnessor<LoginActivity> {
public EditText et_account;
public EditText et_pswd;
public Button btn_login;
public TextView tv_code;
public TextView tv_msg;
public LoginResult result;
public ILoginViewModel viewModel;
@Override
public void bind(final LoginActivity host, Object source) {
if (!Utils.contentViewExist(host)) {
host.setContentView(R.layout.activity_login);
}
et_account = (EditText) host.findViewById(R.id.et_account);
et_pswd = (EditText) host.findViewById(R.id.et_pswd);
btn_login = (Button) host.findViewById(R.id.btn_login);
tv_code = (TextView) host.findViewById(R.id.tv_code);
tv_msg = (TextView) host.findViewById(R.id.tv_msg);
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewModel.onLoginClick(et_account.getText().toString().trim() , et_pswd.getText().toString().trim());
}
});
}
@Override
public void clear() {
this.result = null;
this.viewModel = null;
}
@Override
public void clearAll() {
this.result = null;
this.viewModel = null;
this.et_account = null;
this.et_pswd = null;
this.btn_login = null;
this.tv_code = null;
this.tv_msg = null;
}
@Override
public void bindViewModel(Object viewModel) {
this.viewModel = (ILoginViewModel) viewModel;
}
public void setResult(LoginResult result) {
if (result == null) return;
this.result = result;
BriefnessInjector.injector(tv_code,result.getCode());
BriefnessInjector.injector(tv_msg,result.getMsg());
}
}
該類(lèi)實(shí)現(xiàn)了數(shù)據(jù)綁定较幌,以及向ViewModel發(fā)送消息附帶輸入框中的值。
Briefness的具體用法白翻,請(qǐng)參考https://github.com/hacknife/briefness
下面說(shuō)一說(shuō)BaseActivity
public abstract class BaseActivity<T extends IBaseViewModel,B extends Briefnessor> extends AppCompatActivity implements IBaseView {
protected T viewModel;
protected B briefnessor;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
briefnessor = (B )Briefness.bind(this);
viewModel = createViewModel(briefnessor);
briefnessor.bindViewModel(viewModel);
initView();
}
protected abstract T createViewModel(B briefnessor);
@Override
protected void onDestroy() {
super.onDestroy();
if (viewModel != null)
viewModel.dettachView();
}
protected void initView() {
}
@Override
public Context applicationContext() {
return getApplication();
}
@Override
public Activity context() {
return this;
}
}
BaseActivity中初始化了Briefness并創(chuàng)建ViewModel綁定到Briefness乍炉,并實(shí)現(xiàn)了IBaseView
public interface IBaseView {
Context applicationContext();
Activity context();
}
BaseViewModel繼承AbsViewmodel并實(shí)現(xiàn)IBaseViewModel绢片,持有Briefnessor,View岛琼,Model眷昆。
public abstract class BaseViewModel<V extends IBaseView, M extends IBaseModel, B extends Briefnessor> extends AbsViewModel<V> implements IBaseViewModel {
protected V view;
protected M model;
protected B briefnessor;
public BaseViewModel(V view, B briefnessor) {
this.attachView(view);
this.attachBriefnessor(briefnessor);
this.view = getView();
this.briefnessor = (B) getBriefnessor();
model = createModel();
}
protected abstract M createModel();
@Override
public Context applicationContext() {
return view.applicationContext();
}
@Override
public Activity context() {
return view.context();
}
}
AbsViewModel 的作用主要是釋放相應(yīng)的連接關(guān)系惕澎。
public abstract class AbsViewModel<T> implements IBaseViewModel{
protected WeakReference<T> mViewRef;
protected WeakReference<Briefnessor> mBriefnessorRef;
protected void attachView(T view) {
mViewRef = new WeakReference<T>(view);
}
protected void attachBriefnessor(Briefnessor briefnessor) {
mBriefnessorRef = new WeakReference<Briefnessor>(briefnessor);
}
protected T getView() {
return mViewRef.get();
}
protected Briefnessor getBriefnessor() {
return mBriefnessorRef.get();
}
public boolean isViewAttached() {
return mViewRef != null && mViewRef.get() != null & mBriefnessorRef != null & mBriefnessorRef.get() != null;
}
public void dettachView() {
if (mViewRef != null) {
mViewRef.clear();
mViewRef = null;
}
if (mBriefnessorRef != null) {
mBriefnessorRef.clear();
mBriefnessorRef = null;
}
}
}
BaseModel 持有ViewModel郑临,并實(shí)現(xiàn)了IBaseView崎页。
public abstract class BaseModel<VM extends IBaseViewModel> implements IBaseModel {
protected VM viewModel;
public BaseModel(VM viewModel) {
this.viewModel = viewModel;
}
@Override
public Context applicationContext() {
return viewModel.applicationContext();
}
@Override
public Activity context() {
return viewModel.context();
}
}
寫(xiě)的不好,請(qǐng)多多見(jiàn)諒困檩,畢竟小學(xué)都沒(méi)畢業(yè)??
如果還有什么不明白的祠挫,代碼直通車(chē)https://github.com/hacknife/Briefness/tree/master/example/src/main/java/com/hacknife/demo/mvvm