去年的Google IO 大會上袁滥,Android 團(tuán)隊(duì)發(fā)布了一個數(shù)據(jù)綁定框架(Data Binding Library)。依賴它可以在 Android 項(xiàng)目中實(shí)現(xiàn) MVVM 模式膏潮,其主要功能(解決的問題)有:
1踱讨、可以直接在 layout 布局 xml 文件中綁定數(shù)據(jù)了悴侵,無需再 findViewById 然后手工設(shè)置數(shù)據(jù)了箱叁。
2、也可以用來綁定事件的操作积蔚。
3意鲸、數(shù)據(jù)可以被觀察和設(shè)置,以便在需要的時候使其自動更新。
本 Sample 并沒有嚴(yán)格遵循MVVM或者M(jìn)VP临扮,因?yàn)樗仁褂昧薞iewModel论矾,又使用了Presenter。其總體架構(gòu)圖為:
1杆勇、Presenter 仍然負(fù)責(zé)業(yè)務(wù)邏輯贪壳;
2、View 的顯示和刷新交給 ViewModel 來處理蚜退,ViewModel 和 View 之間的交互通過 Data Binding 來完成(其實(shí)闰靴,本例中并不是完全通過 ViewModel 來跟 View 交互,仍保留有 Presenter 對 View 的操作)钻注;
3蚂且、View 的 XML 文件需要實(shí)現(xiàn) Data Binding。
本文將通過待辦事項(xiàng)列表頁(對象項(xiàng)目中的tasks包)來進(jìn)行分析幅恋。
準(zhǔn)備事項(xiàng)
在 build.gradle 文件中添加:
dataBinding {
enabled = true
}
數(shù)據(jù)綁定
1杏死、XML 文件定義了<data>標(biāo)簽:
<data>
<import type="android.view.View" />
<variable
name="tasks"
type="com.example.android.architecture.blueprints.todoapp.tasks.TasksViewModel" />
<variable
name="actionHandler"
type="com.example.android.architecture.blueprints.todoapp.tasks.TasksContract.Presenter" />
</data>
2、XML 文件使用數(shù)據(jù)綁定:
<TextView
android:id="@+id/filteringLabel"
……
android:text="@{tasks.currentFilteringLabel}" />
<TextView
android:id="@+id/noTasksMain"
……
android:text="@{tasks.noTasksLabel}" />
<LinearLayout
android:id="@+id/noTasks"
……
android:visibility="@{tasks.notEmpty ? View.GONE : View.VISIBLE}" />
……
3捆交、向 ViewModel 中設(shè)置數(shù)據(jù):
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TasksFragBinding tasksFragBinding = TasksFragBinding.inflate(inflater, container, false);
// 在<data>標(biāo)簽中定義的<variable>都會有其 set 方法
tasksFragBinding.setTasks(mTasksViewModel);
tasksFragBinding.setActionHandler(mPresenter);
4淑翼、通知 ViewModel 來進(jìn)行刷新:
public void showTasks(List<Task> tasks) {
mListAdapter.replaceData(tasks);
mTasksViewModel.setTaskListSize(tasks.size());
}
// TasksViewModel 繼承 BaseObservable,調(diào)用其notifyPropertyChanged()方法
public void setTaskListSize(int taskListSize) {
mTaskListSize = taskListSize;
notifyPropertyChanged(BR.noTaskIconRes);
notifyPropertyChanged(BR.noTasksLabel);
notifyPropertyChanged(BR.currentFilteringLabel);
notifyPropertyChanged(BR.notEmpty);
notifyPropertyChanged(BR.tasksAddViewVisible);
}
5品追、當(dāng)然玄括,要實(shí)現(xiàn) XML 中定義的方法:
// TasksViewModel 繼承 BaseObservable,使用 @Bindable 來注解方法
@Bindable
public String getCurrentFilteringLabel() {
switch (mPresenter.getFiltering()) {
case ALL_TASKS:
return mContext.getResources().getString(R.string.label_all);
case ACTIVE_TASKS:
return mContext.getResources().getString(R.string.label_active);
case COMPLETED_TASKS:
return mContext.getResources().getString(R.string.label_completed);
}
return null;
}
@Bindable
public String getNoTasksLabel() {
switch (mPresenter.getFiltering()) {
case ALL_TASKS:
return mContext.getResources().getString(R.string.no_tasks_all);
case ACTIVE_TASKS:
return mContext.getResources().getString(R.string.no_tasks_active);
case COMPLETED_TASKS:
return mContext.getResources().getString(R.string.no_tasks_completed);
}
return null;
}
@Bindable
public boolean isNotEmpty() {
return mTaskListSize > 0;
}
……
事件綁定
數(shù)據(jù)綁定就不需要調(diào)用findViewById()肉瓦,而事件綁定則可以幫助減少setOnClickListener()等這些事件注冊方法遭京。比如,定義 TextView 標(biāo)簽的點(diǎn)擊事件泞莉,調(diào)用了 actionHandler 對象的 addNewTask() 方法哪雕。
<TextView
android:id="@+id/noTasksAdd"
……
android:onClick="@{() -> actionHandler.addNewTask()}"
android:visibility="@{tasks.tasksAddViewVisible ? View.VISIBLE : View.GONE}" />
而該方法則在 TasksPresenter 中進(jìn)行了定義:
@Override
public void addNewTask() {
mTasksView.showAddTask();
}
通過以上分析,可以看出跟mvp最大的區(qū)別是:通過引用 Data Binding 庫鲫趁,簡化了 View 中UI的控制邏輯斯嚎,ViewModel 擔(dān)任了該項(xiàng)職責(zé)。
轉(zhuǎn)載請標(biāo)明出處:http://www.reibang.com/p/9c99a4bf7c9d