StateDataLayout

I intended to write a lib, but turn out it can’t be.

It should be called a architecture to solving the problem than a lib, because it require a lot of constraints. What’s problem ? I’m not in the mood to talk. (If I like it, I’ll do it – as Tùng Mountain said)

Demo Github link: https://github.com/allenatwork/StateDataLayout

A Layout that change state base on response from server.

Layout State:

  • loading
  • error
  • no data
  • have data

Usage

  • Initialize Data layout

In your onCreateView in your fragment, put the following code to intilize StateDataLayout:

stateDataLayout= new StateDataLayout<>(this, inflater);

stateDataLayout .setLayoutRes(getLayoutRes(), R.layout.nodata_layout, R.layout.loading_layout, R.layout.error_layout);
When you start call API, you’ll want to show loading:
     stateDataLayout.bindLoading();
When API response, if success and data return, pass the data into layout:
     stateDataLayout.bindData(data);
And if it error, pass the error message string into layout:
     stateDataLayout.bindError(mes);
  • Define Response Object.

Your response object must implement interface
 
public interface GetInfoData {

    boolean hasData();

}
and sure you have to implemnt hasData() method. Which define the returned data is valid or not (Valid mean has data ?)
  • In your controller class, here is Fragment 

You must implement controller interface:
 
public interface ControllerTask<K> {

    void reload();

     void displayData(K data);

}
K is the class type of response data we said above.
sure you will have to implement two method:
– reload: reload data
– displayData (K data): with the data type K, you (actually) bind it in your view.
That’s it. So simple ,right ?

 

So I started to write a lib (Turned out it can’t be)

All about the “Glide”

dependencies {
    compile 'com.github.bumptech.glide:glide:3.7.0'
}

And …

Glide
.with(context)
.load( url)
.placeholder(R.mipmap.ic_launcher) &nbsp;// Default image load to ImageView
.error(R.mipmap.future_studio_launcher) &nbsp;// If error, ImageView will show this
.fallback( R.drawable.floorplan ) &nbsp;/* If url == null, ImageView will show this (To distinguish with case error by server or internet) &nbsp;*/
.crossFade() &nbsp;// Fade Animation
.into(imageView);
  • crossFace() >< dontAnimate()

Còn nữa … (Glide có nhiều cái rất thú vị)

Tìm hiểu về thư viện network Retrofit (Phần 1)

Retrofit là một network library mới nổi của Square ( khoảng vài năm…) và thường được so sánh với thư viện Volley của Google.
Retrofit là gì ?
A type-safe REST client for Android and Java.
Ko biết diễn giải ra tiếng việt như thế nào, nhưng cứ hiểu nó tương đương với Volley là được rồi. (Mặc dù đi sâu vào so sánh thì hai thư viện này có những mục đích và chức năng khác nhau. Tuy nhiên chưa cần quan tâm đến bây giờ)
Retrofit đã ra đến phiên bản > 2. và khá ổn định. Trước đó có một phiên bản ổn định và được biết tới nhiều là 1.9. Chúng ta sẽ nghiên cứu >2.0 thôi vì còn học cái cũ làm gì.
Để sử dụng Retrofit, ta khai báo trong gradle.

Ở các phiên bản trước, khi khai báo thì retrofit & OkHttp được khai báo như hai module riêng rẽ, tuy nhiên đến 2.0 trở đi thì mặc định retrofit dùng OkHttp làm tầng network (Network Layer) và xây dựng trên nó rồi.
Vì vậy khai báo chung là như một.
(Retrofit chỉ dùng OkHttp để làm tầng network, còn Volley thì linh động hơn, có thể dùng được OkHttp, Appache, v.vv.)
Ngoài ra đi kèm retrofit cung cấp cả gson converter như là một Convert Factory của nỏ.
(Gson là định dạng phổ biến hiện nay nên khai báo thế. Nếu muốn dùng XML thì cũng có thể khai báo XML converter)
Phần khai báo thư viện đã xong. Tiếp theo dùng Retrofit như thế nào.
Ta sẽ tìm hiểu một khái niệm cơ bản & cốt lõi đó là Service Generator. Mục đích của thằng này là để tạo ra một Adapter REST cơ bản cho class/interface của chúng ta.
Code như sau:
Phân tích đoạn code: chúng ta sẽ khai báo base Url của api.
Sau đó tạo ra một OkHttp client.
Sau đó tạo ra một Builder của retrofit sử dụng base url và network layer là Okhttp vừa khởi tạo.
Sau đó sử dụng builder để tạo ra service cho lớp/interface cần tạo.
“Lớp/interface cần tạo” được nhắc đến ở đây là gì ?
Các interface này là những khai báo về method call api. Trong file này chúng ta sẽ khai báo các api với thông tin như: phương thức call api (GET, POST), tham số truyền vào, kiểu truyền vào, giá trị trả về.
(Contributor là một class dữ liệu )
Khi sử dụng, chúng ta sẽ dùng như sau:
Trong đoạn code trên có thể thấy được vai trò của Service Generator. Interface GitHubClient lúc đầu chỉ là một class khai báo các phương thức. Nhờ có Service Generato mà nó mới trở thành một Http client.
Tạm thời tìm hiểu qua về cách sử dụng Retrofit là như vậy. Ở những bài tiếp theo của serrie retrofit sẽ trình bày các vấn đề sau:
– Cách  truyền tham số vào một API Retrofit.
– Call api Retrofit đồng bộ & bắt đồng bộ.
– So sánh Volley & Retrofit.

Mô hình MVP trong lập trình Android

photo

Trong Android, Activity hoặc Fragment là đóng vai trò là khối xử lí tất cả các logic của chương trình: quản lí vòng đời của ứng dụng, tìm view,animation, input event, lấy dữ liệu từ network hoặc database, xử lí các logic v.v.v. Khi chương trình còn đơn giản, việc xử lí sẽ không có vấn đề gì. Tuy nhiên, khi chúng ta muốn tăng thêm các tính năng cho màn hình, số lượng dòng code xử lí sẽ tăng lên. Đồng thời, bạn sẽ phải xử lí các tình huống nếu rolate device/configuration change/ user nhấn nút home. Mọi thứ sẽ được xử lí trong Activity/Fragment.

Như vậy có thể nói nếu chúng ta cứ đơn thuần xử lí mọi thứ trong activity/fragment thì sẽ không phải là một mô hình tốt. Chúng ta cần một mô hình phát triển đơn giản – dễ maintain – tách rời – dễ test.

Có nhiều mô hình lập trình được đề xuất cho Android, trong đó nổi bật nhất và tôi sẽ đề cập đến ngày hôm nay là mô hình MVP.

  1. Tư tưởng của mô hình MVP
  2. MVP # MVC ở chỗ nào
  3. Làm sao để apply MVP vào Android
  4. Lợi ích của MVP

Tư tưởng của mô hình MVP

MVP đại diện cho Model – View – Presenter.

Như đã nói, theo mô hình lập trình thông thường, nghĩa là xử lí tất cả mọi thứ được xử lí trong Activity/Fragment, thì khi app trở nên phức tạp, code của bạn sẽ trở nên rối rắm. Mô hình lập trình MVP sẽ phân chia công việc mà A/F ôm đồm ở trên thành từng lớp xử lí riêng biệt. Cụ thể là:

M – Model: lớp xử lí dữ liệu. Lớp này sẽ chịu trách nhiệm lấy dữ liệu từ database hoặc network một cách bất đồng bộ. Sau đó sẽ trả về dữ liệu cho Presenter thông qua các hàm callback.

V- View: lớp xử lí view. Lớp này chịu trách nhiệm tìm view (bind view), đưa dữ liệu vào view, animation, kiểm soát các input event của user và gửi cho present các event

P – Presenter: lớp này sẽ là lớp xử lí các bussiness logic. Đây là sẽ lớp trung gian có thể giao tiếp được với hai lớp M & V (chú ý M – V ko  giao tiếp trực tiếp với nhau). Khi lớp View nhận một input event sẽ gửi sự kiện xuống lớp P, lớp P lấy sẽ liệu từ lớp Model và gửi lại cho lớp V và hướng dẫn lớp V cách hiển thị.

Nếu làm đúng, trong lớp P sẽ chỉ có code Java. Mọi code liên quan đến Android sdk sẽ được thực hiện trong lớp View hoặc lớp Model. Như vậy, sẽ dễ để viết unittest (Local test cho lớp P chỉ toàn Java và instrument test cho lớp View). Đồng thời code của chúng ta sẽ rõ ràng rành mạch, xử lí riêng biệt từng phần giữa business logic, view. Chương trình sẽ được chia nhỏ ra, các task lớn được chia thành task nhỏ.

MVP # MVC chỗ nào 

đang cập nhật …

Làm sao để apply MVP vào trong chương trình Android của bạn ? 

Khi đã hiểu được tư tưởng của MVP, mỗi người sẽ có một cách áp dụng khác nhau vào chương trình của mình. (Tôi đã đọc nhiều bài viết về MVP của các tác giả, và nó không giống nhau, nhưng tư tưởng thì vẫn là một. Ngoài ra họ còn sử dụng nhiều thư viện khác nhau để hoàn thành mô hình MVP của mình. Ở đây tôi sẽ ko dùng thư viện nào).

Để đưa ra một ví dụ về việc apply MVP, tôi sẽ implement một chương trình đơn giản. Đó là hiển thị một list các user với dữ liệu user lấy từ server về. Rât đơn giản nhưng sẽ phải xử lí các vấn đề sau:

  • Lấy dữ liệu từ server về – hiển thị vào một list
  • Xử lí các trường hợp kết nối server lỗi, dữ liệu trả về không có gì
  • Có chức năng reload
  • Xử lí configuration change

Link  github : https://github.com/allenatwork/Allen-Demo-Android-MVP

Giải thích: Ứng dụng demo này gồm có 3 màn hình.

Đầu tiên là màn hình home, màn hình about (Ko cần quan tâm hai màn hình này)

Cần quan tâm là màn hình list User. Đây là nơi chúng ta thực hiện việc implement mô hình MVP.

Cần chú ý đến 4 lớp: ListUserHelper.java, ListUserPresenter.java, ListUserView.java, ListUserFragment.java

Đọc tên lớp các bạn có thể hình dung ra được đâu là M – V – P.

=====================================================

V

Trong ListUserView chính là một interface khai báo các hành động của View:

reload(), showNoData(), showError(), displayListUser();

Và fragment sẽ implement interface này.

=====================================================

M

ListUserHelper là class thực hiện các thao tác load dữ liệu (Ở đây là load data from remote server về ).  Dữ liệu sẽ được lấy một cách bất đồng bộ, khi dữ liệu trả về sẽ được gửi trả lại cho Presenter thông qua một hàm callback. (Nếu lỗi cũng gửi lại thông báo là lỗi) Chi tiết dữ liệu được gửi hãy đọc trong class

=======================================================

P

ListUserPresenter là class sẽ đóng vai trò là Presenter làm công tác trung gian giữa M – V. Lớp này khi khởi tạo sẽ có hai biến con là ListUserHelper và ListUserView. Và business logic sẽ được implement sử dụng hai biến này. ListUserPresenter sẽ dược khởi tạo ở Fragment và được fragment truyền vào hai tham số này.

==========================================================

ListUserFragment là lớp implement interface ListUserView (đúng theo tư tưởng Activity/Fragment đóng vai trò là V) và sẽ implement các method xử lí logic về view: khi reload sẽ thế nào, khi noData sẽ thế nào, hiển thị list user thế nào. Trong class này sẽ ko có logic xử lí về business, chỉ có logic xử lí về view và handle các OnClick. Khi nhận được sự kiện OnClick nó sẽ gọi Presenter thực hiện phương thức phù hợp.

Như vậy tôi đã giải thích qua về ví dụ implement MVP pattern cho Android. Chi tiết có thể đọc thêm trong code.

Ngoài ra có một vấn đề đó là xử lí khi configuration change: rolate device, ẩn app & don’t keep activity. Dữ liệu về user sẽ được lưu lại khi onSaveInstanceState và lấy ra ở onCreate. Nếu khi chúng ta đọc ra và gọi hàm displayList với data lấy ra sau khi lưu, việc này sẽ dược xử lí ở Fragment và lúc này Fragment đã thực hiện một logic business. Tôi cho rằng hành động này ko hợp lí. Các dữ liệu nên có sự quản lí bởi Model. Vì vậy khi khởi tạo Model ListUserHelper sẽ được truyền vào dữ liệu là list user.

 

Lợi ích của mô hình MVP

  • Code rõ ràng rành mạch, các task lớn được chia ra nhiều task nhỏ -> dễ test/debug
  • Phân chia rành mạch giữa các loại xử lí : xử lí dữ liệu / xử lí view / xử lí business logic

Tài liệu tham khảo