Android Architecture Components: Paging Library
Bài đăng này đã không được cập nhật trong 3 năm
Nhiều ứng dụng của chúng ta cần load rất nhiều data information từ Database. Queries đến Database có thể mất nhiều thời gian và sử dụng rất nhiều bộ nhớ. Do đó Google đã release thư viện mới là Paging Library có thể giúp bạn sử lý vấn đề này.
Main Component of Paging Library
Main component of Paging Library là PagedListAdapter
kế thừa từ RecyclerViewAdapter
, PagedList
, và DataSource
.
DataSourde
DataSource là interface cho pager source để cung cấp các dữ liệu. Khi sử dụng bạn phải implement 1 trong 2 lại datasourde: DataSource
và TiledDataSource
nó sẽ được sử dụng khi bạn load N data từ N-1 data.
- Sử dụng
KeyedDataSource
nếu bạn cấn sử dụng N data để lấy N+1 data. Ví dụ: khi bạn muốn fetch comment of a post status of Facebook bạn cần biết được id của comment N để lấy được comment N+1 - Sử dụng
TiledDataSource
nếu bạn muốn fetch từ bất kỳ vị trí nào bạn muốn trong your data store. Class này sẽ support request tập các dữ liệu bất đầu từ vị trí bạn muốn. Ví dụ 20 item từ vị trí 1200 loadCount()
: bạn cũng có thể implement một phương thức khác, phương thứcloadCount()
cho bạn biết có một số lượng hữu hạn hay vô hạn item bạn cần hiển thị trong your list.
Nếu bạn sử dụng Room Persistent Library để quản lý database, nó sẽ tự động tạo DataSource
class.
Ví dụ: queries dưới đây trả về TiledDataSource
:
@Query("select * from users WHERE age > :age order by name DESC, id ASC")
TiledDataSource<User> usersOlderThan(int age);
PagedList
The PagedList là thành phần tự động load data và provide tín hiệu để update data trên RecyclerViewAdapter. Data sẽ được tự động load trên background thread và được sử dụng trên main thread. Nó hỗ trợ cả: list scroll vô hạn và list có giới hạn. Bạn cũng có thể thiết lập một vài cấu hình: Size of first page and số item khi load
PagedListAdapter
Class implement từ RecyclerView.Adapter
đại diện cho PagedList:family_mmgg:. Ví dụ khi 1 page mới được load thì PagedListAdapter
sẽ báo hiệu cho RecyclerView
data đã đến, RecyclerView sẽ update lại data.
PagedListAdapter
sử dụng background để tính toán sự thay đổi từ PagedList
, sau đó RecyclerView sẽ thực hiện những thay đổi cần thiết.
Paging Library Example
- Add Component Architecture to your project
Open
build.gradle
trong project và add lines bên dưới
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
}
}
Add Architecture Component
Mở build.gradle
trong app/
add lines bên dưới
dependencies {
....
implementation 'com.android.support:appcompat-v7:26.1.0'
//For Lifecycles, LiveData, and ViewModel
implementation 'android.arch.lifecycle:runtime:1.0.0'
implementation 'android.arch.lifecycle:extensions:1.0.0-alpha9-1'
annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha9-1"
//For Room
implementation 'android.arch.persistence.room:runtime:1.0.0-alpha9-1'
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha9-1"
//For Paging
implementation 'android.arch.paging:runtime:1.0.0-alpha1'
}
- Create DataSource
Create Entity
@Entity
public class User {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "user_id")
public long userId;
@ColumnInfo(name = "first_name")
public String firstName;
public String address;
.....
}
Data Access Objects (DAO)
Để đơn giản trong connection giữa DataSource và RecyclerView, chúng ta sử dụng LivePagedListProvider
.
@Dao
public interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
public void insertAll(List<User> users);
@Query("SELECT * FROM User")
public abstract LivePagedListProvider<Integer,User> usersByFirstName();
}
Create DataBase
@Database(entities = {User.class}, version = 1)
abstract public class AppDatabase extends RoomDatabase {
public static final String DATABASE_NAME = "UserDb";
public abstract UserDao userDao();
}
- Create ViewModel
ViewModel
sẽ extends từViewModel
của Architecture Component và sử dụng chúng để tham chiếu tớiLiveData
củaPagedList
. Chúng ta sẽ lấy tham chiếu đó từ DAO bằng cách gọi methodgetUsers()
. Config cấu hình mà bạn muốn. Ví dụ: Size của page là 50, và size của mối lần load data là 50
public class UserViewModel extends ViewModel {
public LiveData<PagedList<User>> userList;
public UserViewModel() {
}
public void init(UserDao userDao) {
userList = userDao.usersByFirstName().create(0,
new PagedList.Config.Builder()
.setEnablePlaceholders(true)
.setPageSize(50)
.setPrefetchDistance(50)
.build());
}
}
Trong onCreate của Activity chúng ta sẽ tham chiếu tới ViewModel và RecyclerView
RecyclerView recyclerView = findViewById(R.id.userList);
LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(llm);
UserViewModel viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
viewModel.init(userDao);
final UserAdapter userUserAdapter = new UserAdapter();
viewModel.userList.observe(this, pagedList -> {
userUserAdapter.setList(pagedList);
});
recyclerView.setAdapter(userUserAdapter);
- Create Adapter
Để nói cho
PagedListAdapter
biết là làm thế nào để biết sự khác nhau giữa 2 phần từ, implement classDiffCallback
@Entity
public class User {
public static DiffCallback<User> DIFF_CALLBACK = new DiffCallback<User>() {
@Override
public boolean areItemsTheSame(@NonNull User oldItem, @NonNull User newItem) {
return oldItem.userId == newItem.userId;
}
@Override
public boolean areContentsTheSame(@NonNull User oldItem, @NonNull User newItem) {
return oldItem.equals(newItem);
}
};
.....
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
User user = (User) obj;
return user.userId == this.userId && user.firstName == this.firstName;
}
}
Create Adapter
public class UserAdapter extends PagedListAdapter<User, UserAdapter.UserItemViewHolder> {
protected UserAdapter() {
super(User.DIFF_CALLBACK);
}
@Override
public UserItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.item_user_list, parent, false);
return new UserItemViewHolder(view);
}
@Override
public void onBindViewHolder(UserItemViewHolder holder, int position) {
User user= getItem(position);
if(user!=null) {
holder.bindTo(user);
}
}
}
Xem code tại đây 5. Kết thúc Android có nhiều khái niệm và thành phần mới với thành phần kiến trúc. Nhưng điều đó có nghĩa là bạn có thể tách riêng chúng. Vì vậy nếu bạn muốn, bạn sẽ chỉ có thể sử dụng vòng đời, LiveData và PagedList hoặc chỉ ViewModel hoặc chỉ Room Persistent. Nhưng bạn cũng có thể sử dụng chúng với nhau. Vậy hãy bắt đầu sử dụng Architecture Components để tạo ra một kiến trúc có thể phù hợp cho ứng dụng của bạn.
All rights reserved