Cách phân trang trong Recyclerview

Cách phân trang trong Recyclerview

Khi lập trình các ứng dụng bạn sẽ thường gặp các trường hợp là dữ liệu của bạn quá nhiều và nếu hiển thị tất cả lên màn hình thì sẽ rất rối mắt và xem không được thoải mái tạo cảm giác khó chịu cho người sử dụng và tải toàn bộ dữ liệu về sẽ rẩt nặng vậy trong trường hợp này bạn phải làm thế nào.

I.Phân trang là gì?

Trong trường hợp này bạn phải phân trang cho dữ liệu như Youtube ấy bạn thấy đấy dữ liệu nó vô cùng lớn và không thể tải hết về được nên Youtube sẽ tải một số lượng giới hạn danh sách các video trong một trang tức là trang bạn đang xem sẽ có bao nhiêu cái video đc hiển thị trong danh sách ví dụ như 10 cái chẳng hạn và khi bạn kéo tới video cuối cùng trong danh sách thì nó sẽ 10 video của trang thứ 2 về và cứ thể cho tới trang cuối cùng cơ mà bạn xem hết được các trang của youtube thì mình nghĩ bạn là siêu nhân rồi đấy.

II.Cách phân trang

OK. Ý tưởng rất đơn giản chia dữ liệu ra thành các trang và tải chúng về ví dụ như bạn có 20 bản ghi trong CSDL và mỗi trang trên ứng dụng bạn sẽ hiển thị 10 bản ghi vậy là bạn sẽ phân thành 2 trang.

Đây ví dụ luôn cho nó nóng.

item_layout.xml

Code:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardElevation="10dp"
    android:layout_margin="8dp"
    >

    <LinearLayout
        android:orientation="vertical"
        android:padding="10dp"
        android:background="?android:selectableItemBackground"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/txtName"
            android:text="Name"
            android:textColor="@android:color/black"
            android:textSize="16sp"
            android:textStyle="bold"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/txtLength"
            android:text="Length"
            android:textColor="@android:color/black"
            android:textSize="14sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>

</android.support.v7.widget.CardView>

item_loading.xml

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

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        />

</LinearLayout>

main_activity.xml

Code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

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

Trên đây là vài file xml giao diện cần thiết cho demo chắc mình không cần giải thích nữa.

Giờ code cái linh hồn cho demo nà.

Đầu tên làm cái Interface ILoadmore. Chắc nhiều bạn hỏi ta cần cái Interface này để làm gì thì mình xin thưa nó dùng để callback dữ liệu khi được tải về đấy.

Code:
public interface ILoadmore {
    void onLoadMore();
}

Giờ tạo đối tượng Item.

Code:
public class Item {
    private String name;
    private int length;

    public Item(String name, int length) {
        this.name = name;
        this.length = length;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }
}

Còn đây là cái Adapter cho Recyclerview nà mình giải thích trong code luôn rồi nha.

Code:
package com.mms.vietsid.loaddulieudongrecycleview;

import android.app.Activity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

/**
 * Created by Akinosora on 06/03/2018.
 */
class LoadingViewHolder extends RecyclerView.ViewHolder {
    public ProgressBar progressBar;


    public LoadingViewHolder(View itemView) {
        super(itemView);
        progressBar = itemView.findViewById(R.id.progressBar);
    }
}

class ItemViewHolder extends RecyclerView.ViewHolder {
    public TextView name, lenght;

    public ItemViewHolder(View itemView) {
        super(itemView);
        name = itemView.findViewById(R.id.txtName);
        lenght = itemView.findViewById(R.id.txtLength);
    }
}

public class AdapterRecycler extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private final int VIEW_TYPE_ITEM = 0, VIEW_TYPE_LOADING = 1;
    ILoadmore loadMore;
    boolean isLoading;
    Activity activity;
    List<Item> items;
    int visibleThreshold = 5;
    int lastVisibleItem, totalItemCount;

    public AdapterRecycler(Activity activity, List<Item> items, RecyclerView recyclerView) {
        this.activity = activity;
        this.items = items;

        final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                totalItemCount = linearLayoutManager.getItemCount(); // Lấy tổng số lượng item đang có
                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition(); // Lấy vị trí của item cuối cùng
                if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) // Nếu không phải trạng thái loading và tổng số lượng item bé hơn hoặc bằng vị trí item cuối + số lượng item tối đa hiển thị
                {
                    if (loadMore != null)
                        loadMore.onLoadMore(); // Gọi callback interface Loadmore
                    isLoading = true;
                }

            }
        });
    }

    @Override
    public int getItemViewType(int position) {
        return items.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;// So sánh nếu item được get tại vị trí này là null thì view đó là loading view , ngược lại là item
    }

    public void setLoadMore(ILoadmore loadMore) {
        this.loadMore = loadMore;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
        if (viewType == VIEW_TYPE_ITEM) {
            View view = LayoutInflater.from(activity)
                    .inflate(R.layout.item_layout, parent, false);
            final RecyclerView.ViewHolder holder = new ItemViewHolder(view);
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(activity, "" + items.get(holder.getPosition()).getName(), Toast.LENGTH_SHORT).show();
                }
            });
            return holder;
        } else if (viewType == VIEW_TYPE_LOADING) {
            View view = LayoutInflater.from(activity)
                    .inflate(R.layout.item_loading, parent, false);

            return new LoadingViewHolder(view);
        }

        return null;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof ItemViewHolder) {
            Item item = items.get(position);
            ItemViewHolder viewHolder = (ItemViewHolder) holder;
            viewHolder.name.setText(items.get(position).getName());
            viewHolder.lenght.setText(String.valueOf(items.get(position).getLength()));
        } else if (holder instanceof LoadingViewHolder) {
            LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
            loadingViewHolder.progressBar.setIndeterminate(true);
        }
    }

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

    public void setLoader() {
        isLoading = false;
    }
}

Xong cái Adapter thì ta triển lên MainActivity chơi.

Code:
package com.mms.vietsid.loaddulieudongrecycleview;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private List<Item> itemList = new ArrayList<>();
    private AdapterRecycler adapterRecycler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = findViewById(R.id.RecycleviewList);
        random10Data();
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapterRecycler = new AdapterRecycler(this, itemList, recyclerView);
        recyclerView.setAdapter(adapterRecycler);
        adapterRecycler.setLoadMore(new ILoadmore() {
            @Override
            public void onLoadMore() {
                if (itemList.size() <= 50)// Bạn có thể change max giá trị load ở đây , load tới số lượng như này thì có kéo nữa cũng không load nữa , bỏ điều kiện này đi thì nó cứ thế mà load
                {
                    itemList.add(null); // Add 1 cái null , để làm gì ? Quay lại cái Adapter của chúng ta mà thấy , nếu gặp item null thì nó sẽ coi đó là Loading View
                    adapterRecycler.notifyItemInserted(itemList.size() - 1);// Báo với adapter là có sự thay đổi
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {// Cái này là mình giả lập , bạn có thể replace cái Handler này với hàm fetch tới Web API hoặc database của các bạn để load dữ liệu
                            itemList.remove(itemList.size() - 1);//Gỡ bỏ thằng null vừa thêm vào khi nãy
                            adapterRecycler.notifyItemRemoved(itemList.size());// Báo với adapter là có sự thay đổi

                            // Thêm dữ liệu ngẫu nhiên
                            int index = itemList.size();
                            int end = index + 10;
                            for (int i = index; i < end; i++) {
                                String name = UUID.randomUUID().toString();
                                Item item = new Item(name, name.length());
                                itemList.add(item);
                            }
                            adapterRecycler.notifyDataSetChanged();
                            adapterRecycler.setLoader();
                        }
                    }, 3000);// Thời gian load dữ liệu
                } else {
                    // Khi đã load hết toàn bộ dữ liệu ta thông báo đã tải xong
                    Toast.makeText(MainActivity.this, "Load data completed !", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    private void random10Data() {
        for (int i = 0; i < 10; i++) {
            String name = UUID.randomUUID().toString(); // Tạo 1 chuỗi UUID ngẫu nhiên, UUID là gì thì hỏi google-sensei
            Item item = new Item(name, name.length()); // Tạo mới 1 item model
            itemList.add(item);// Thêm vào danh sách =))
        }
    }
}

Xong giờ bạn hãy thử chạy ứng dụng lên xem nó phân trang như thế nào nhé, cảm ơn các bạn đã theo dõi hẹn gặp lại các bạn ở các tuts tiếp theo.