2、快速上手【最火開源框架MVVMHabit簡單集成】

最火開源框架MVVMhabit
一. 準備工作
二. 快速上手

三. 數據綁定

  1. TextView綁定
  2. onClick綁定
  3. ImageView綁定
  4. ListView綁定
  5. RecyclerView綁定

四. 其他

  1. toolbar頭部標題
  2. 底部tabBar第三方按鈕

2.1、第一個Activity

以大家都熟悉的登錄操作為例:三個文件LoginActivty.javaLoginViewModel.java、activity_login.xml

2.1.1、關聯ViewModel

在activity_login.xml中關聯LoginViewModel。

<layout>
    <data>
        <variable
            type="com.goldze.mvvmhabit.ui.login.LoginViewModel"
            name="viewModel"
        />
    </data>
    .....

</layout>

variable - type:類的全路徑
variable - name:變量名

2.1.2、繼承BaseActivity

LoginActivity繼承BaseActivity

public class LoginActivity extends BaseActivity<ActivityLoginBinding, LoginViewModel> {
    //ActivityLoginBinding類是databinding框架自定生成的,對activity_login.xml
    @Override
    public int initContentView(Bundle savedInstanceState) {
        return R.layout.activity_login;
    }

    @Override
    public int initVariableId() {
        return BR.viewModel;
    }

    @Override
    public LoginViewModel initViewModel() {
        //View持有ViewModel的引用,如果沒有特殊業(yè)務處理,這個方法可以不重寫
        return ViewModelProviders.of(this).get(LoginViewModel.class);
    }
}

保存activity_login.xml后databinding會生成一個ActivityLoginBinding類。(如果沒有生成,試著點擊Build->Clean Project)

BaseActivity是一個抽象類,有兩個泛型參數,一個是ViewDataBinding,另一個是BaseViewModel,上面的ActivityLoginBinding則是繼承的ViewDataBinding作為第一個泛型約束,LoginViewModel繼承BaseViewModel作為第二個泛型約束。

重寫B(tài)aseActivity的二個抽象方法

initContentView() 返回界面layout的id
initVariableId() 返回變量的id,對應activity_login中name="viewModel",就像一個控件的id,可以使用R.id.xxx,這里的BR跟R文件一樣,由系統生成,使用BR.xxx找到這個ViewModel的id。

選擇性重寫initViewModel()方法,返回ViewModel對象

@Override
public LoginViewModel initViewModel() {
    //View持有ViewModel的引用,如果沒有特殊業(yè)務處理,這個方法可以不重寫
    return ViewModelProviders.of(this).get(LoginViewModel.class);
}

注意: 不重寫initViewModel(),默認會創(chuàng)建LoginActivity中第二個泛型約束的LoginViewModel,如果沒有指定第二個泛型,則會創(chuàng)建BaseViewModel

2.1.3、繼承BaseViewModel

LoginViewModel繼承BaseViewModel

public class LoginViewModel extends BaseViewModel {
    public LoginViewModel(@NonNull Application application) {
        super(application);
    }
    ....
}

BaseViewModel與BaseActivity通過LiveData來處理常用UI邏輯,即可在ViewModel中使用父類的showDialog()、startActivity()等方法。在這個LoginViewModel中就可以盡情的寫你的邏輯了!

BaseFragment的使用和BaseActivity一樣,詳情參考Demo。

2.2、數據綁定

擁有databinding框架自帶的雙向綁定,也有擴展

2.2.1、傳統綁定

綁定用戶名:

在LoginViewModel中定義

//用戶名的綁定
public ObservableField<String> userName = new ObservableField<>("");

在用戶名EditText標簽中綁定

android:text="@={viewModel.userName}"

這樣一來,輸入框中輸入了什么,userName.get()的內容就是什么,userName.set("")設置什么,輸入框中就顯示什么。 注意: @符號后面需要加=號才能達到雙向綁定效果;userName需要是public的,不然viewModel無法找到它。

點擊事件綁定:

在LoginViewModel中定義

//登錄按鈕的點擊事件
public View.OnClickListener loginOnClick = new View.OnClickListener() {
    @Override
    public void onClick(View v) {

    }
};

在登錄按鈕標簽中綁定

android:onClick="@{viewModel.loginOnClick}"

這樣一來,用戶的點擊事件直接被回調到ViewModel層了,更好的維護了業(yè)務邏輯

這就是強大的databinding框架雙向綁定的特性,不用再給控件定義id,setText(),setOnClickListener()。

但是,光有這些,完全滿足不了我們復雜業(yè)務的需求??!MVVMHabit閃亮登場:它有一套自定義的綁定規(guī)則,可以滿足大部分的場景需求,請繼續(xù)往下看。

2.2.2、自定義綁定

還拿點擊事件說吧,不用傳統的綁定方式,使用自定義的點擊事件綁定。

在LoginViewModel中定義

//登錄按鈕的點擊事件
public BindingCommand loginOnClickCommand = new BindingCommand(new BindingAction() {
    @Override
    public void call() {

    }
});

在activity_login中定義命名空間

xmlns:binding="http://schemas.android.com/apk/res-auto"

在登錄按鈕標簽中綁定

binding:onClickCommand="@{viewModel.loginOnClickCommand}"

這和原本傳統的綁定不是一樣嗎?不,這其實是有差別的。使用這種形式的綁定,在原本事件綁定的基礎之上,帶有防重復點擊的功能,1秒內多次點擊也只會執(zhí)行一次操作。如果不需要防重復點擊,可以加入這條屬性

binding:isThrottleFirst="@{Boolean.TRUE}"

那這功能是在哪里做的呢?答案在下面的代碼中。

//防重復點擊間隔(秒)
public static final int CLICK_INTERVAL = 1;

/**
* requireAll 是意思是是否需要綁定全部參數, false為否
* View的onClick事件綁定
* onClickCommand 綁定的命令,
* isThrottleFirst 是否開啟防止過快點擊
*/
@BindingAdapter(value = {"onClickCommand", "isThrottleFirst"}, requireAll = false)
public static void onClickCommand(View view, final BindingCommand clickCommand, final boolean isThrottleFirst) {
    if (isThrottleFirst) {
        RxView.clicks(view)
        .subscribe(new Consumer<Object>() {
            @Override
            public void accept(Object object) throws Exception {
                if (clickCommand != null) {
                    clickCommand.execute();
                }
            }
        });
    } else {
        RxView.clicks(view)
        .throttleFirst(CLICK_INTERVAL, TimeUnit.SECONDS)//1秒鐘內只允許點擊1次
        .subscribe(new Consumer<Object>() {
            @Override
            public void accept(Object object) throws Exception {
                if (clickCommand != null) {
                    clickCommand.execute();
                }
            }
        });
    }
}

onClickCommand方法是自定義的,使用@BindingAdapter注解來標明這是一個綁定方法。在方法中使用了RxView來增強view的clicks事件,.throttleFirst()限制訂閱者在指定的時間內重復執(zhí)行,最后通過BindingCommand將事件回調出去,就好比有一種攔截器,在點擊時先做一下判斷,然后再把事件沿著他原有的方向傳遞。

是不是覺得有點意思,好戲還在后頭呢!

2.2.3、自定義ImageView圖片加載

綁定圖片路徑:

在ViewModel中定義

public String imgUrl = "http://img0.imgtn.bdimg.com/it/u=2183314203,562241301&fm=26&gp=0.jpg";

在ImageView標簽中

binding:url="@{viewModel.imgUrl}"

url是圖片路徑,這樣綁定后,這個ImageView就會去顯示這張圖片,不限網絡圖片還是本地圖片。


如果需要給一個默認加載中的圖片,可以加這一句

binding:placeholderRes="@{R.mipmap.ic_launcher_round}"

R文件需要在data標簽中導入使用,如:<import type="com.goldze.mvvmhabit.R" />

BindingAdapter中的實現:創(chuàng)建自定義文件ViewAdapter.java寫入下面代碼實現BindingAdapter

@BindingAdapter(value = {"url", "placeholderRes"}, requireAll = false)
public static void setImageUri(ImageView imageView, String url, int placeholderRes) {
    if (!TextUtils.isEmpty(url)) {
        //使用Glide框架加載圖片
        Glide.with(imageView.getContext())
                .load(url)
                .apply(new RequestOptions().placeholder(placeholderRes))
                .into(imageView);
    }
}

很簡單就自定義了一個ImageView圖片加載的綁定,學會這種方式,可自定義擴展。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容