12/08/2018, 17:52
Sử dụng MVVM và Android Architecture Components
MVC, MVP, MVVM là các Architecture pattern được sử dụng bởi developer. Tùy vào yêu cầu và size project mà developer chọn 1 architecture pattern mà mình cảm thấy phù hợp và thoải mái để áp dụng. Mới đây Google đã giới thiệu thêm 1 architecture mới Android Architecture Components bao gồm 4 components ...
MVC, MVP, MVVM là các Architecture pattern được sử dụng bởi developer. Tùy vào yêu cầu và size project mà developer chọn 1 architecture pattern mà mình cảm thấy phù hợp và thoải mái để áp dụng. Mới đây Google đã giới thiệu thêm 1 architecture mới Android Architecture Components bao gồm 4 components chính LifeCycle, ViewModel, Livedata, Room
mở module build.gradle và thêm dòng sau
//Architecture components implementation "android.arch.lifecycle:extensions:1.0.0" annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
- LiveData là observable holder class. Đặc biệt LiveData còn biết được lifecycle state của các component của app, việc này đảm bảo LiveData chỉ update dữ liệu, thông báo cho các observer khi chúng trong trạng thái active, tránh memory leak. Tham khảo link sau để biết thêm chi tiết
// setting value public LiveData<News> getNews(String source) { final MutableLiveData<News> data = new MutableLiveData<>(); getNews(source).enqueue(new Callback<News>() { @Override public void onResponse(Call<News> call, Response<News> response) { data.setValue(response.body()); } @Override public void onFailure(Call<News> call, Throwable t) { data.setValue(null); } }); return data; } //listening for change in <Object>. // this would be in ui layer getObservableProject().observe(this, new Observer<Object>() { @Override public void onChanged(@Nullable Object obj) { // handle changes } });
- Trong ví dụ trên News object được lấy bởi Api call và được wrap trong LiveData. UI layer sẽ observe LiveData object khi có sự thay đổi.
- Chuẩn bị dữ liệu cho tầng UI
- Đóng vai trò trung gian giữa UI và Repository
- Khi thiết bị xoay màn hình (Activity restart) ViewModel sẽ không thay đổi, không bị destroy. Sau khi activity destroy và tạo lại sẽ nhận lại ViewModel trước đó mà không tạo lại
- ViewModel có thể giao tiếp với tầng View mà không cần callback interface
// View model for News Object public class NewsViewModel extends AndroidViewModel { private final LiveData<News> newsLiveData; public ObservableField<News> news = new ObservableField<>(); public NewsViewModel(@NonNull Application application) { super(application); // a differnt source can be passed, here i am passing techcrunch newsLiveData = NewsRepository.getInstance().getNews("techcrunch"); } public LiveData<News> getObservableProject() { return newsLiveData; } } // accessing NewsModel Object final NewsViewModel viewModel = ViewModelProviders.of(this, factory) .get(NewsViewModel.class); viewModel.getObservableProject().observe(this, new Observer<News>() { @Override public void onChanged(@Nullable News news) { // } });
- Trong ví dụ trên News object được wrap trong NewsViewModel. Lưu ý, ta không nên có reference đến view trong ViewModel để tránh memory leak bởi ViewModel không bị destroy khi activity destroy
- Tại tầng view (Activity, Fragment) sẽ chỉ chứa code liên quan đến UI, business logic và webservice call sẽ được di chuyển sang tầng ViewModel và Repository
- Binding ViewModel to View được thực hiện thông qua layout XML bằng cách thêm tag layout như sau:
// ViewModel reference in XML <data> <variable name="article" type="com.gauravgoyal.mvvm_with_testing.service.model.Article" /> </data> //using Viewmodel to display data <TextView android:id="@+id/title" android:layout_awidth="wrap_content" android:layout_height="wrap_content" android:contentDescription="@string/app_name" android:text="@{article.title}" android:textSize="@dimen/news_text" android:textStyle="bold" />
- trong ví dụ trên ta khai báo object Article và sử dụng biến đó để update title cho TextView. Việc thực hiện update title được viết trong cú pháp "@{}". Tuy nhiên, trong một số trường hợp ta muốn thực hiện 1 số việc phức tạp hơn, ta có thể custom sử dụng anotation BindingAdapter như sau:
//xml <TextView android:id="@+id/publishedAt" android:layout_awidth="wrap_content" android:layout_height="wrap_content" app:dateText="@{article.publishedAt}" android:textSize="@dimen/news_text" /> //handling dateText property @BindingAdapter("dateText") public static void convertToDate(TextView view, String date) { view.setText(DateUtils.Companion.convertToDateString(date)); }
nguồn