Hi dev, apakah kalian pernah memperhatikan bahwa di aplikasi Instagram terdapat circle progress bar manakala konten recyclerview digulir keatas.

Ini adalah fitur yang sangat keren dan perlu untuk ditambahkan ke aplikasi Kalian, jika aplikasi Kalian menggunakan recyclerview yang memuat data dari server. Dem UX yang lebih baik, maka pengguna perlu diberi tahu bahwa proses pemuatan data dari server sedang berlangsung.
Sejujurnya, progress dialog overlay dilengkapi teks “Memuat.. atau Harap Tunggu..” adalah metode jadul yang udah usang. Komunitas Android Developer telah menemukan solusi baru yang jauh lebih keren untuk mengatasi masalah ini, diantaranya menerapkan circle progress bar, snackbar, dll. Sebagai indikasi kepada pengguna bahwa ada sesuatu yang terjadi di latar belakang.

Ini memberikan pengalaman Pengguna yang lebih kaya dan responsif. Siapa yang tidak menginginkannya?!
Cara mengimplementasikan pagination di Android Recyclerview
Langkah-langkah di bawah ini adalah praktek terbaik sesuai kenyataan industri pengembangan aplikasi Android.
- Menambahkan recyclerview dan library dependensi.
- Menyiapkan recyclerview di Activity
- Membuat dua file tata letak: Satu untuk item data dan satu lagi untuk indikator progress.
- Membuat adaptor untuk recyclerview
- Membuat listener untuk adapter recyclerview
- Setel adaptor recyclerview dan listener
Tambahkan recyclerview and design library dependency
Pertama-tama, Anda perlu menambahkan dependensi recyclerview dan library desain seperti yang disebutkan di bawah ini:
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.support:design:27.1.1'
Pastikan mereka memiliki versi yang sama.. jika tidak, ini dapat menyebabkan beberapa error saat runtime. Kemudian sinkronkan file gradle dan tunggu hingga selesai.
Siapkan recyclerview kosong di Activity
Di aktivitas / fragmen tempat Anda ingin menampilkan recyclerview, buka file layout dan tambahkan recylcerview. Tata letak saya terlihat seperti ini:
<?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.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Sekarang buka file java dan siapkan recyclerview dengan menambahkan LinearLayoutManger sebagai pengelola tata letaknya. Inilah MainActivity.java saya.
package com.ayusch.blogexamples.view;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import com.ayusch.blogexamples.R;
import com.ayusch.blogexamples.adapter.CustomAdapter;
import com.ayusch.blogexamples.listeners.InfiniteScrollListener;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity{
RecyclerView recyclerView;
ArrayList<Integer> data = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerview);
LinearLayoutManager manager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(manager);
}
}
Buat dua file tata letak: Satu untuk item data dan satu lagi untuk progress bar
Cara kerjanya adalah, progress bar yang Anda lihat ditambahkan ke recyclerview sebagai entri android recyclerview biasa. Ini sama halnya entri data Anda yang lain. Satu-satunya perbedaan adalah, saat data dimuat dari server, item tersebut dihapus dari android recyclerview dan recyclerview diperbarui.
Berikut adalah tata letak row_item.xml
<?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="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
android:text="1"
android:textSize="28sp" />
</LinearLayout>
Saya akan menampilkan angka di tengah item. Baris Anda bisa jauh lebih kompleks dari ini, tetapi ini bukan tujuan dari tutorial ini.
Ini adalah row_progress.xml saya
<?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="wrap_content"
android:gravity="center"
android:orientation="vertical">
<ProgressBar
android:id="@+id/progressbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Buat adaptor khusus untuk recyclerview
Sekarang inilah bagian yang berdaging!! Di sinilah keterampilan pengembangan android Anda akan diuji dan pengetahuan Anda tentang recyclerviews dan recyclerview adapters dalam pengembangan android akan berguna.
Sekarang kita perlu membuat 3 ViewHolders
- A base view holder
- A view holder for our data item
- A view holder for progressbar
Buat kelas dalam di dalam CustomAdapter dengan nama CustomViewHolder dan extend dari RecyclerView.ViewHolder. Implementasikan metodenya dengan mengklik ALT + Enter.
Buat kelas dalam kedua di dalam CustomAdapter dengan nama DataViewHolder dan extend dari CustomViewHolder. Terapkan semua metodenya juga.
Terakhir, buat kelas dalam ketiga di dalam CustomAdapter bernama ProgressViewHolder dan extend dari CustomViewHolder. Terapkan semua metodenya juga.
package com.ayusch.blogexamples.adapter;
import android.support.annotation.NonNull;
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 com.ayusch.blogexamples.R;
import java.util.ArrayList;
public class CustomAdapter extends RecyclerView.Adapter{
class DataViewHolder extends CustomViewHolder {
public DataViewHolder(View itemView) {
super(itemView);
}
}
class ProgressViewHolder extends CustomViewHolder {
public ProgressViewHolder(View itemView) {
super(itemView);
}
}
class CustomViewHolder extends RecyclerView.ViewHolder {
public CustomViewHolder(View itemView) {
super(itemView);
}
}
}
Ingat saya telah memberi tahu Anda untuk tidak membuat modifier public ke CustomAdapter
, kami akan melakukannya sekarang. Tambahkan jenis umum CustomViewHolder
saat Anda memperluas dari RecyclerView.Adapter dan terapkan metode berikut.
package com.ayusch.blogexamples.adapter;
import android.support.annotation.NonNull;
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 com.ayusch.blogexamples.R;
import java.util.ArrayList;
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomViewHolder> {
private ArrayList<Integer> dataList;
public CustomAdapter(ArrayList<Integer> dataList) {
this.dataList = dataList;
}
@NonNull
@Override
public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
}
@Override
public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return dataList.size();
}
class DataViewHolder extends CustomViewHolder {
public DataViewHolder(View itemView) {
super(itemView);
}
}
class ProgressViewHolder extends CustomViewHolder {
public ProgressViewHolder(View itemView) {
super(itemView);
}
}
class CustomViewHolder extends RecyclerView.ViewHolder {
public CustomViewHolder(View itemView) {
super(itemView);
}
}
}
Saya telah menambahkan konstruktor yang akan mengambil ArrayList data sebagai parameternya.
Kita perlu mengganti satu metode lagi di sini: getItemViewType()
Tekan CTRL Enter dan pilih Override Methods dan pilih getItemViewType () Sekarang di sinilah letak triknya !! Kita harus mengelabui adaptor dengan berpikir bahwa item data sedang ditambahkan ke recyclerview, saat kita ingin menampilkan bilah kemajuan. Tapi bagaimana cara membedakan data asli dan palsu? Nah, barang palsu yang akan kita tambahkan, akan menjadi objek null. Jadi, dalam metode getItemViewType()
, kita bisa mengembalikan tipe tampilan berdasarkan apakah item tersebut palsu (null) atau data nyata. ViewType yang kita kembalikan di sini diperoleh dalam metode onCreateViewHolder()
(lihat parameter terakhir).
Kami harus mengembalikan pemegang tampilan di sini berdasarkan apakah kami harus menampilkan baris data atau bilah kemajuan. Jadi, pertama-tama dalam metode getItemViewType()
, terapkan pemeriksaan null pada item data Anda dan kembalikan nilai tertentu berdasarkan padanya. Akan terlihat seperti ini:
@Override
public int getItemViewType(int position) {
if (dataList.get(position) != null)
return VIEW_TYPE_ITEM;
else
return VIEW_TYPE_LOADING;
}
IEW_TYPE_ITEM dan VIEW_TYPE_LOADING
adalah bidang konstanta bilangan bulat di kelas CustomAdapter. Sekarang, dalam metode pembuatan CustomAdapter, kita harus mengembalikan pemegang tampilan berdasarkan jenis tampilan. Beginilah tampilan metode onCreateViewHolder Anda:
public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View root = null;
if (viewType == VIEW_TYPE_ITEM) {
root = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_item, parent, false);
return new DataViewHolder(root);
} else {
root = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_progress, parent, false);
return new ProgressViewHolder(root);
}
}
Sekarang kita perlu mengikat data ke layout dalam metode onBindViewHolder.
@Override
public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) {
if (holder instanceof DataViewHolder) {
((DataViewHolder) holder).tvNumber.setText(dataList.get(position) + "");
}else{
//Do whatever you want. Or nothing !!
}
}
Kami akan menambahkan 3 metode utilitas ke adaptor tersebut.
- Untuk menambahkan data palsu untuk menunjukkan progress bar
- Untuk menghapus data palsu
- Untuk menambahkan data aktual yang diterima setelah pemuatan selesai.
Tambahkan metode bernama addNullData()
ke adaptor khusus:
public void addNullData() {
dataList.add(null);
notifyItemInserted(dataList.size() - 1);
}
Sekarang tambahkan metode removeNullData()
public void removeNull() {
dataList.remove(dataList.size() - 1);
notifyItemRemoved(dataList.size());
}
Sekarang untuk menambahkan data baru yang kami terima dari server, kami menambahkan metode bernama addData
(ArrayList dataList).
public void addData(ArrayList<Integer> integersList) {
dataList.addAll(integersList);
notifyDataSetChanged();
}
Dan kelas CustomAdapter
kami akhirnya selesai!!
Membuat pemroses gulir tak terbatas ke recyclerview
Kami akan menambahkan InfiniteScrollListener
ke recyclerview. Ini akan memicu metode loadMore()
di dalam aktivitas kita ketika semua data yang tersedia telah ditampilkan di layar.
Buat kelas baru bernama InfiniteScrollListener
seperti yang ditunjukkan di bawah ini:
package com.ayusch.blogexamples.listeners;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
public class InfiniteScrollListener extends RecyclerView.OnScrollListener {
private final static int VISIBLE_THRESHOLD = 2;
private LinearLayoutManager linearLayoutManager;
private boolean loading; // LOAD MORE Progress dialog
private OnLoadMoreListener listener;
private boolean pauseListening = false;
private boolean END_OF_FEED_ADDED = false;
private int NUM_LOAD_ITEMS = 10;
public InfiniteScrollListener(LinearLayoutManager linearLayoutManager, OnLoadMoreListener listener) {
this.linearLayoutManager = linearLayoutManager;
this.listener = listener;
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dx == 0 && dy == 0)
return;
int totalItemCount = linearLayoutManager.getItemCount();
int lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!loading && totalItemCount <= lastVisibleItem + VISIBLE_THRESHOLD && totalItemCount != 0 && !END_OF_FEED_ADDED && !pauseListening) {
if (listener != null) {
listener.onLoadMore();
}
loading = true;
}
}
public void setLoaded() {
loading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void addEndOfRequests() {
this.END_OF_FEED_ADDED = true;
}
public void pauseScrollListener(boolean pauseListening) {
this.pauseListening = pauseListening;
}
}
Setel adaptor recyclerview dan pemroses gulir
Terakhir, saatnya menyetel adaptor dan pemroses gulir kami. Ubah kode seperti di bawah ini:
public class MainActivity extends AppCompatActivity implements InfiniteScrollListener.OnLoadMoreListener {
RecyclerView recyclerView;
ArrayList<Integer> data = new ArrayList<>();
InfiniteScrollListener infiniteScrollListener;
CustomAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerview);
LinearLayoutManager manager = new LinearLayoutManager(this);
infiniteScrollListener = new InfiniteScrollListener(manager, this);
infiniteScrollListener.setLoaded();
recyclerView.setLayoutManager(manager);
recyclerView.addOnScrollListener(infiniteScrollListener);
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
for (int i = 0; i < 10; i++) {
data.add(i);
}
adapter = new CustomAdapter(data);
recyclerView.setAdapter(adapter);
}
@Override
public void onLoadMore() {
adapter.addNullData();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
adapter.removeNull();
ArrayList<Integer> newData = new ArrayList<>();
for (int i = 0; i < 10; i++) {
newData.add(i);
}
adapter.addData(newData);
infiniteScrollListener.setLoaded();
}
}, 2000);
}
}
Di onLoadMethod
, Anda akan melakukan panggilan jaringan atau apa pun untuk mengambil kumpulan data berikutnya dan menambahkannya ke recyclerview. Demi contoh ini, saya menambahkan data dummy dan memberikan penundaan dua detik untuk meniru permintaan jaringan.
Beginilah tampilan MainActivity.java terakhir:
public class MainActivity extends AppCompatActivity implements InfiniteScrollListener.OnLoadMoreListener {
RecyclerView recyclerView;
ArrayList<Integer> data = new ArrayList<>();
InfiniteScrollListener infiniteScrollListener;
CustomAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerview);
LinearLayoutManager manager = new LinearLayoutManager(this);
infiniteScrollListener = new InfiniteScrollListener(manager, this);
infiniteScrollListener.setLoaded();
recyclerView.setLayoutManager(manager);
recyclerView.addOnScrollListener(infiniteScrollListener);
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
for (int i = 0; i < 10; i++) {
data.add(i);
}
adapter = new CustomAdapter(data);
recyclerView.setAdapter(adapter);
}
@Override
public void onLoadMore() {
adapter.addNullData();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
adapter.removeNull();
ArrayList<Integer> newData = new ArrayList<>();
for (int i = 0; i < 10; i++) {
newData.add(i);
}
adapter.addData(newData);
infiniteScrollListener.setLoaded();
}
}, 2000);
}
}
Oke, beres!