之前在Day4提過Google將會讓Data Binding也有lifecycle-aware效果,於是,新的Data Binding V2讓我們可以直接用LiveData來取代ObservableField,很方便地達成Data Binding的lifecycle-aware。
現在V2還在測試中,可在Android Studio 3.1 Canary 6以上的版本先行試用。
要啟用V2版需先升級一下環境:
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.1.0-alpha07'
}
}
gradle-wrapper.properties
中的distributionUrl最低須為gradle-4.4。distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
gradle.properties
中啟用V2。android.databinding.enableV2=true
重新Build專案,如果Build完發現原本Data Binding的getRoot()
等method不能用,可以用File -> Invalidate Cache/Restart重啟Android Studio就會正常了。
現在可以直接用LiveData取代ObservableField,假設要用Data Binding顯示讀取狀態的話,原寫法:
// ViewModel
public final ObservableField<Boolean> isLoading = new ObservableField<>();
isLoading.set(true);
// View
binding.setViewModel(viewModel);
新的寫法:
// ViewModel
public final MutableLiveData<Boolean> isLoading = new MutableLiveData<>();
isLoading.postValue(true);
// View
binding.setViewModel(viewModel);
binding.setLifecycleOwner(this);
用LiveData取代並加上setLifecycleOwner
就讓Data Binding具有lifecycle-aware性質了。
那接著實際套用到我們的專案上,RepoViewModel中的LiveData repo在之前已經包裝過使其同時擁有資料及讀取狀態,只要把它改成public就可以用在Data Binding上。
public class RepoViewModel extends ViewModel {
public final LiveData<Resource<List<Repo>>> repos;
...
}
在layout檔中設置<data>
,並在ProgressBar用repos.status
取得讀取狀態。
<?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">
<data>
<import type="android.view.View" />
<import type="ivankuo.com.itbon2018.data.model.Status" />
<variable
name="viewModel"
type="ivankuo.com.itbon2018.ui.RepoViewModel" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
...>
...
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:visibleGone="@{viewModel.repos.status == Status.LOADING}"
... />
</android.support.constraint.ConstraintLayout>
</layout>
最後在RepoFragment中,綁定ViewModel和LifecycleOwner:
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
viewModel = ViewModelProviders.of(this, factory).get(RepoViewModel.class);
binding.setViewModel(viewModel);
binding.setLifecycleOwner(this);
viewModel.getRepos().observe(...)
}
完成,之後ProgressBar就只會在View處於前景的時候才變更顯示狀態。
當初在#issue34看到yigit大神說將來會讓Data Binding具有lifecycle-aware性質時,還不曉得實際上會怎麼達成,結果是用個人覺得很好的做法:直接用LiveData取代,這樣除了有lifecycle-aware以外,也可以少寫幾個ObserverbleField在ViewModel中,讓程式更簡潔一致。
GitHub source code:
https://github.com/IvanBean/ITBon2018/tree/day24-data-binding-v2
Reference:
Architecture Components: How to use LiveData with Data Binding?