Sử dụng retrofit2 và mô hình MVP trong phát triển ứng dụng android

Trong bài viết này mình sẽ kết hợp sử dụng MVP và retrofit2, thành một demo hoàn chỉnh.

1.Giới thiệu:

– Sử dụng retrofit2 xem tại đây.
– Bài viết về MVP xem tại đây.

2.Các bước thực hiện:

  • Tạo project mới.
  • Import các thư viện cần sử dụng
  • Tạo cấu trúc project, các package
  • Tạo giao diện
  • Code API
  • Code Presenter
  • Code Adapter

3.Bắt đầu:

  • Các thư viện cần thiết
   compile 'com.android.support:recyclerview-v7:24.2.1'
    compile 'com.android.support:cardview-v7:24.2.1'
    compile 'com.google.code.gson:gson:2.6.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.squareup.retrofit2:retrofit:2.0.2'
    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'

Ở đây mình sử dụng ButterKnife bạn nào chưa biết dùng thì xem ở đây.

  • Tạo cấu trúc project theo hình bên dưới:

 

  • Tạo giao diện
    • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="pixa.com.demomvp.view.MainActivity">

    <Button
        android:text="@string/btnGetData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btnGetData" />

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recyclerView" />

</LinearLayout>
  • item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="2"
    android:orientation="vertical">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:id="@+id/cardView"
        android:layout_weight="1"
        android:layout_marginBottom="0dp"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        android:layout_marginTop="9dp"
        card_view:cardElevation="0.01dp"
        card_view:cardCornerRadius="10dp">

        <LinearLayout
            android:id="@+id/top_layout"
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/img_Thumnail"
                android:layout_width="match_parent"
                android:layout_height="150dp"
                android:scaleType="fitXY" />

            <TextView
                android:id="@+id/tv_Name"
                android:layout_width="fill_parent"
                android:layout_height="40dp"
                android:layout_gravity="bottom"
                android:textColor="@android:color/black"
                android:textSize="16sp"
                android:typeface="serif"
                android:gravity="center_vertical|center" />
        </LinearLayout>
    </android.support.v7.widget.CardView>
</LinearLayout>
  • Tạo lớp Products.java nằm trong package model.

Sử dụng 2 hàm chuyển đổi json thành Object thông qua thư viện Gson.

public class Products {

    @SerializedName("id_product")
    public int idProduct;
    @SerializedName("product_name")
    public String productName;
    @SerializedName("decription")
    public String decription;
    @SerializedName("price")
    public String price;
    @SerializedName("thumnail")
    public String thumnail;

    private static Products getProduct (JSONObject jsonObject){
        return new Gson().fromJson(jsonObject.toString(),Products.class);
    }

    public  static ArrayList<Products> getAllProduct(JSONArray jsonArray) throws JSONException {
        ArrayList<Products> arrayList = new ArrayList<>();
        for(int i = 0; i<jsonArray.length(); i++) {
            arrayList.add(getProduct(jsonArray.getJSONObject(i)));
        }
        return arrayList;
    }
  // Các bạn tự thêm contructor, getter setter vào nhé
  • Code API

-Tạo file Constant.java nằm trang package config:

public class Constant {
    public  static String URL_PRODUCT = "http://dev.androidcoban.com/blog/";
}

-Tạo interface APIService.java

public interface APIService {

    @GET("getallproducts.php")
    Call<ResponseBody> getAllProduct ();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(Constant.URL_PRODUCT)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
}

– Tạo lớp APIServiceIml.java  triển khai APIService:

Dữ liệu trả về  được đưa vào trong listener để xử lý bên presenter.

public class APIServiceIml{
    String TAG = APIServiceIml.class.getSimpleName();
    APIService apiService;

    public void getAllProduct(final FetchDataCallback dataCallback) {
        apiService = APIService.retrofit.create(APIService.class);
        Call<ResponseBody> getProduct = apiService.getAllProduct();
        getProduct.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    JSONArray obj = new JSONArray(response.body().string());
                    dataCallback.onFetchSuccess(Products.getAllProduct(obj));
                } catch (Exception e) {
                    dataCallback.onFetchFault(e);
                }

            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e(TAG, t.toString());
                dataCallback.onFetchFault(new Exception(t));
            }
        });
    }
    
}

-Trong pakage listener tạo interface FectDataCallBack để nhận dữ liệu trả về từ lớp ApiIml ở trên gồm 2 hàm onFetchSuccess nhận dữ liệu trả về, và onFetchFault nhận lỗi trả về.

public interface FetchDataCallback {
    void onFetchSuccess(ArrayList<Products> list);
    void onFetchFault(Exception e);
}
  • Code Presenter

Tạo một lớp BasePresenter.java lớp này dùng để dùng chung cho tất cả các presenter khác.

public class BasePresenter {
    protected Context context;

    public BasePresenter(Context context) {
        this.context = context;
    }
}

Tạo lớp ProductPresenter.java extends BasePresenter.java tùy theo nhu cầu, tùy công ty mà lớp Presenter mỗi người viết khác nhau.

public class ProductPresenter extends BasePresenter{
    String TAG = ProductPresenter.class.getSimpleName();
    private RecyclerView.LayoutManager layoutManager;
    private ProductAdapter productAdapter;
    private ArrayList<Products> productsList;
    APIServiceIml apiServiceIml;

    public ProductPresenter(Context context, RecyclerView recyclerView) {
        super(context);
        apiServiceIml = new APIServiceIml();
        layoutManager = new GridLayoutManager(context,2);
        recyclerView.setLayoutManager(layoutManager);
        productsList = new ArrayList<>();
        productAdapter = new ProductAdapter(productsList,context);
        recyclerView.setAdapter(productAdapter);
    }

    /**
     * parse data
     * Noti adapter
     * */
    public void fetchData() {
        //Call method getAllProduct in API
        apiServiceIml.getAllProduct(new FetchDataCallback() {
            @Override
            public void onFetchSuccess(ArrayList<Products> list) {
                Log.d(TAG, list.toString());
                productsList.addAll(list);
                productAdapter.notifyDataSetChanged();
            }

            @Override
            public void onFetchFault(Exception e) {

            }
        });
    }
}
  • Code Adapter cho recycler view (Xem thêm recyclerview tại đây)

Tạo  ProductAdapter.java

public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductHolder> {
    private List<Products> listProduct;
    private Context context;

    public ProductAdapter(List<Products> listProduct ,Context context) {
        this.listProduct = listProduct;
        this.context  = context;
    }

    @Override
    public ProductHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item,parent,false);
        return new ProductHolder(view);
    }

    @Override
    public void onBindViewHolder(ProductHolder holder, int position) {
        Products products = listProduct.get(position);
        holder.txtName.setText(products.getProductName());
        Glide.with(context).load(products.getThumnail())
                .centerCrop()
                .into(holder.imgThumnal);
    }

    @Override
    public int getItemCount() {
        return listProduct.size();
    }

    class ProductHolder extends RecyclerView.ViewHolder{
        @BindView(R.id.img_Thumnail) ImageView imgThumnal;
        @BindView(R.id.tv_Name) TextView txtName;
        public ProductHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this,itemView);
        }
    }
}

Cuối cùng quay lại MainActivity.java gọi Presenter ra để sử dụng.

public class MainActivity extends AppCompatActivity {
    @BindView(R.id.recyclerView) RecyclerView recyclerView;
    private ProductPresenter productPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        productPresenter = new ProductPresenter(this,recyclerView);
    }
    @OnClick(R.id.btnGetData)
    public void getData() {
        productPresenter.fetchData();
    }
}

4.KẾT LUẬN

Hiện nay đa số các project đều sử dụng mô hình MVP vì vậy để đáp ứng nhu cầu công việc, mỗi lập trình viên nên tìm hiểu và phát triển code theo hướng MVP để dễ dàng tiếp cận công việc sau này.

Nguyễn Linh

Chia sẻ để cùng tiến bộ...

Bình luận đã bị khoá.