Android Architecture Patterns (phần 3): Model-View-ViewModel
PHẦN 1 – PHẦN 2
Sau bốn mẫu designs khác nhau trong sáu tháng đầu của sự phát triển của các ứng dụng upday, chúng ta đã học được một bài học quan trọng đó là chúng ta cần một architecture pattern mà nó cho phép “react” nhanh chóng khi có những thay đổi trong design!
Và giải pháp cuối cùng mà chúng tôi chọn là Model-View-ViewModel. Hãy cùng khám phá MVVM là gì, cách chúng ta áp dụng nó tại upday và những gì đã làm nó trở nên “perfect” đến như vậy
Pattern Model-View-ViewModel
Những yếu tố chính trong pattern MVVM:
- View – Mang chức năng thông báo cho ViewModel về những actions của người dùng.
- ViewModel – Hiển thị streams của những data liên quan đến View
- DataModel – abstracts những nguồn data. ViewModel kết hợp với DataModel sẽ có được data và save data.
Thoáng nhìn qua, MVVM dường như rất giống với mô hình Model-View-Presenter pattern, vì cả hai pattern này đã abstract rất tốt state và behavior của View. Presentation Model abstract một View độc lập với 1 nền tảng iao diện người dùng (UI) riêng biệt, trong khi đó pattern MVVM được tạo ra để đơn giản hóa việc lập trình event driven của giao diện người dùng (UI).
Nếu pattern MVP đồng nghĩa là Presenter yêu cầu trực tiếp là View phải hiển thị những gì, thì đối với MVVM, ViewModel cho ta thấy được nhiều dòng sự kiện (event streams) mà View có thể kết nối vào. Nói cách khác, giống như Presenter, ViewModel không cần phải giữ một tham chiếu đến View . Điều này cũng có nghĩa rằng hiện nay, tất cả các giao diện mà pattern MVP yêu cầu đang giảm.
View cũng mang chức năng thông báo cho ViewModel về các actions khác nhau. Vì vậy, pattern MVVM hỗ trợ two-way data binding giữa View và ViewModel và có một sự liện hệ theo kiểu “many-to-one” giữa View và ViewModel. View có một tham chiếu đến ViewModel nhưng ViewModel lại không fcó thông tin nào vê View. Khách hàng của dữ liệu cần được biết về producer này, nhưng producer – ViewModel – lại không biết, và không quan tâm ai là tiếp nhận data.

Model-View-ViewModel at upday
Nhìn sơ qua những bài post của Android trên blog upday, bạn sẽ ngay lập tức cho ta biết được rằng library yêu thích chính là: RxJava. Vì vậy, không có gì lạ, bởi vì RxJava là nền tảng dcủa code upday! Phần event driven được yêu cầu bởi MVVM sẽ được thực hiện bằngObservable
của RxJava. Đây là cách chúng tôi áp dụng MVVM trong ứng dụng Android tại upday, với sự hỗ trợ của RxJava:
DataModel
DataModel thể hiện data dễ consume thông qua các event streams – đó là các Observable
của RxJava. Nó thường bao hàm data từ nhiều nguồn khác nhau, như các layer network,database và các tham chiếu đã chia sẻ và hiển thị data dễ consum đến những ai đang cần. Những DataModel giữ toàn bộ business logic.
Chúng ta muốn nhấn mạnh về nguyên tắc single responsiblity tạo ra một DataModel cho mọi tính năng trong app. Ví dụ, chúng ta có một ArticleDataModel mà compose những output của nó từ API service và database layer. DataModel này xử lý business logic và đảm bảo rằng những thông tin mới nhất từ các database được lấy ra bằng cách áp dụng age filter.
ViewModel
ViewModel là một model cho View của các app: một abstraction của View. ViewModel lấy các dữ liệu cần thiết từ DataModel, áp dụng logic UI và sau đó hiển thị data có liên quan với View. Tương tự như DataModel, ViewModel hiển thị data thông qua những Observable
Chúng ta đã học được 2 thứ về ViewModel, đó là:
- ViewModel nên hiển thị những state cho View, chứ không phải chỉ là những event. Ví dụ, nếu chúng ta cần để hiển thị tên và địa chỉ email của một
User
, chứ không phải là tạo ra hai stream, thì chúng ta tạo ra một đối tượngDisplayableUser
mà chỉ gói gọn trong hai mảng là tên và địa chỉ mail. Stream sẽ luôn luôn hiển thị tên hoặc những thay đổi trong email. Bằngcách này, chúng ta sẽ đảm bảo được rằng View sẽ luôn luôn hiển thị trạng thái
hiện tại củaUser
. - Chúng ta cần phải bảo đảm rằng mọi action của người dùng phải thông qua ViewModel và bất kỳ logic nào có thể xảy ra của View phải được di chuyển trong ViewModel.
Tham khảo thêm tại các lỗi thông dụng trong MVVM + RxJava.
View
View là giao diện người dùng thực tế trong các app. Nó có thể là một Activity
, một Fragment
hoặc bất kỳ Android View
tùy chỉnh. Đối với Activities
và Fragment
, chúng ta đang binding và unbinding từ những nguồn event trênonResume()
và onPause()
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
private final CompositeSubscription mSubscription = new CompositeSubscription ( ) ;
@ Override
public void < strong class = "markup--strong markup--pre-strong" > onResume < / strong > ( ) {
super . onResume ( ) ;
mSubscription . add ( mViewModel . getSomeData ( )
. observeOn ( AndroidSchedulers . mainThread ( ) )
. subscribe ( this :: updateView ,
this :: handleError ) ) ;
}
@ Override
public void < strong class = "markup--strong markup--pre-strong" > onPause < / strong > ( ) {
mSubscription . clear ( ) ;
super . onPause ( ) ;
}
|
Nếu MVVM View là một Android View
tùy chỉnh, thì binding được thực hiện trong constructor. Để đảm bảo rằng các subscription vẫn chưa được lưu lại, dẫn đến tình trạng rò rỉ bộ nhớ, unbinding xảy ra trong onDetachedFromWindow
.
1
2
3
|
private final CompositeSubscription mSubscription = new CompositeSubscription ( ) ;
|
1
2
3
4
5
6
7
8
9
|
public MyView ( Context context , MyViewModel viewModel ) {
. . .
mSubscription . add ( mViewModel . getSomeData ( )
. observeOn ( AndroidSchedulers . mainThread ( ) )
. subscribe ( this :: updateView ,
this :: handleError ) ) ;
}
|
1
2
3
4
5
6
7
8
|
< a class = "markup--anchor markup--pre-anchor" title = "Twitter profile for @Override" href = "http://twitter.com/Override" target = "_blank" rel = "nofollow noopener" data - href = "http://twitter.com/Override" > @ Override < / a >
public void < strong class = "markup--strong markup--pre-strong" > onDetachedFromWindow < / strong > ( ) {
mSubscription . clear ( ) ;
super . onDetachedFromWindow ( ) ;
}
}
|
Testability Of The Model-View-ViewModel Classes
Một trong những lý do quan trọng khiến chúng ta yêu thích pattern Model-View-ViewModel là vì nó rất dễ test.
DataModel
Việc sử dụng phép nghịch đảo của control pattern, được ứng dụng rất nhiều trong mã code, và sự thiếu hụt của bất kỳ class Android tạo thuận lợi cho việc thực hiện các unit test của DataModel.
ViewModel
Views và các unit test như là hai loại consumers của dữ liệu khác nhau so với ViewModel. ViewModel được tách biệt hoàn toàn với UI hay bất kỳ những classes Android, do đó unit test rất dễ dàng.
Hãy xem xét ví dụ sau đây, nơi ViewModel chỉ hiển thị một số dữ liệu từ DataModel:
1
2
3
4
|
public class < strong class = "markup--strong markup--pre-strong" > ViewModel < / strong > {
private final IDataModel mDataModel ;
|
1
2
3
4
5
|
public ViewModel ( IDataModel dataModel ) {
mDataModel = dataModel ;
}
|
1
2
3
4
5
6
|
public Observable & lt ; Data & gt ; getSomeData ( ) {
return mDataModel . getSomeData ( ) ;
}
}
|
Tests dành cho ViewModel rất dễ thực hiện. Với sự hỗ trợ của Mockito, chúng ta đang sao chép DataModel và chúng ta kiểm soát các dữ liệu trả về cho những methods đã được sử dụng. Sau đó, đảm bảo rằng khi chúng ta subscribe các Observable được trả về bởi getSomeData()
, data sẽ được phát ra.
1
2
3
|
public class < strong class = "markup--strong markup--pre-strong" > ViewModelTest < / strong > {
|
1
2
3
4
5
|
@ Mock
private IDataModel mDataModel ;
private ViewModel mViewModel ;
|
1
2
3
4
5
|
@ Before
public void setUp ( ) throws Exception {
MockitoAnnotations . initMocks ( this ) ;
|
1
2
3
4
|
mViewModel = new ViewModel ( mDataModel ) ;
}
|
1
2
3
4
5
6
7
8
9
10
|
@ Test
public void < strong class = "markup--strong markup--pre-strong" > testGetSomeData_emitsCorrectData < / strong > ( ) {
SomeData data = new SomeData ( ) ;
Mockito . when ( mDataModel . getSomeData ( ) )
. thenReturn ( Observable . just ( data ) ) ;
TestSubscriber & lt ; SomeData & gt ; testSubscriber =
new TestSubscriber & lt ; & gt ; ( ) ;
|
1
2
3
|
mViewModel . getSomeData ( ) . subscribe ( testSubscriber ) ;
|
1
2
3
4
5
|
testSubscriber . assertValue ( data ) ;
}
}
|
Nếu ViewModel cần truy cập vào các class Android class, chúng ta tạo ra những wrapper gọi là các Provider
. Ví dụ, đối với các resources của Android, chúng ta tạo ra một IResourceProvider
mà nó hiển thị những methods như String getString(@StringRes final int id)
. Việc thực hiện IResourceProvider
sẽ chứa một tham chiếu đến Context
, nhưng ViewModel sẽ chỉ đề cập đến 1 IResourceProvider
được thêm vào.
Như đã đề cập ở trên, thì chúng ta đang tạo ra những model object để giữ trạng thái data, cho phép mức độ testabilitycao hơn và việc quản lý dữ liệu được hiển thị bởi ViewModel.
View
Ví dụ logic trong UI là tối thiểu, rất dễ test Views với Espresso. Chúng ta cũng đang sử dụng những library như DaggerMock và MockWebServer để cải thiện sự ổn định của những lần tests UI
MVVM có phải là 1 giải pháp đúng đắn?
Chúng ta đã sử dụng MVVM cùng với RxJava trong gần một năm nay. Kể từ khi View chỉ là một consumer của các ViewModel, rất dễ thay thế các yếu tố UI khác nhau với những thay đổi nhỏ trong những class khác.
Chúng ta cũng đã nhận ra tầm quan trọng khi phân chia các vấn đề, và chúng ta nên chia nhỏ các code nhiều hơn, tạo ra những View nhỏ và ViewModels nhỏ mà chỉ có những trách nhiệm cụ thể. ViewModels được thêm vào Views. Điều này có nghĩa rằng chúng ta thường chỉ thêm Views trong XML UI, mà không thực hiện bất kỳ thay đổi nào khác. Vì vậy, khi những yêu cầu của UI thay đổi một lần nữa, thì chúng ta có thể dễ dàng thay thế một số Views với những Views mới.
Kết luận
MVVM kết hợp những ưu điểm của việc phân chia các vấn đề mà MVP mang lại, đồng thời tận dụng những lợi thế của những data binding. Kết quả là một pattern – nơi mà model thực hiện càng nhiều operation càng tốt – sẽ giảm thiểu logic trong View.
Sau khi design thay đổi trong “giai đoạn trứng nước” của app upday, chúng ta sẽ chuyển sang MVVM trong “giai đoạn trưởng thành” của upday – một giai đoạn mà từ những sai lầm, chúng ta học được rất nhiều. Và giở đây, chúng ta có thể tự hào về một app mà nó đã chứng minh được khả năng “chống chịu” trước lần redesign. khác Và cuối cùng chúng ta đã sắp được gọi upday là một app “trưởng thành”.
Nguồn: Medium.com
- SGO Giải pháp thông minh cho các công ty vận chuyển, logistics thuê ngoài
- Tra cứu thông tin đăng kiểm cơ giới
- Ứng dụng quản lý garage trên smartphone và tablet
- Bán vé máy bay thông qua smartphone và tablet, smart TV
- Hệ thống quản lý vận tải ( S-TMS ) thông minh
- Phần mềm quản lý cho thuê xe ô tô thường có những tính năng gì?
- Mua vé xe, đặt vé xe trên smartphone, smart TV
- Phần mềm CRM (phần mềm quản lý khách hàng) cho lĩnh vực vận tải, hậu cần thường gồm những gì?
- Quản lý giao vận thông minh
- Hệ thống chấm công từ xa thông minh qua vệ tinh STracking
- Quản lý phương tiện cá nhân trên smartphone
- Điều hành hãng xe công nghệ, ứng dụng đặt xe trên smartphone tương tự Uber, Grab,...
- Lời giải cho xe trống chiều về – vấn đề nan giải của ngành vận tải Việt Nam
- Tra cứu thông tin tàu thuyền, lịch xuất cảng của từng tàu
- Phần mềm quản lý xe thường có những tính năng gì?
- Tra cứu tàu biển
- Ứng dụng quản lý vận tải trên smartphone
- Phân hệ Quản lý Đội xe (Fleet Management) trong một hệ thống ERP thường có gì?
- Tính năng cơ bản của một hệ thống giám sát hành trình, hộp đen và ứng dụng điều hành trong vận tải
- Hệ thống điều hành, tìm gọi và quản lý xe sử dụng công nghệ mới
- Giao vận, Logistic
DVMS chuyên:
- Tư vấn, xây dựng, chuyển giao công nghệ Blockchain, mạng xã hội,...
- Tư vấn ứng dụng cho smartphone và máy tính bảng, tư vấn ứng dụng vận tải thông minh, thực tế ảo, game mobile,...
- Tư vấn các hệ thống theo mô hình kinh tế chia sẻ như Uber, Grab, ứng dụng giúp việc,...
- Xây dựng các giải pháp quản lý vận tải, quản lý xe công vụ, quản lý xe doanh nghiệp, phần mềm và ứng dụng logistics, kho vận, vé xe điện tử,...
- Tư vấn và xây dựng mạng xã hội, tư vấn giải pháp CNTT cho doanh nghiệp, startup,...
Vì sao chọn DVMS?
- DVMS nắm vững nhiều công nghệ phần mềm, mạng và viễn thông. Như Payment gateway, SMS gateway, GIS, VOIP, iOS, Android, Blackberry, Windows Phone, cloud computing,…
- DVMS có kinh nghiệm triển khai các hệ thống trên các nền tảng điện toán đám mây nổi tiếng như Google, Amazon, Microsoft,…
- DVMS có kinh nghiệm thực tế tư vấn, xây dựng, triển khai, chuyển giao, gia công các giải pháp phần mềm cho khách hàng Việt Nam, USA, Singapore, Germany, France, các tập đoàn của nước ngoài tại Việt Nam,…
Quý khách xem Hồ sơ năng lực của DVMS tại đây >>
Quý khách gửi yêu cầu tư vấn và báo giá tại đây >>