Android Architecture Components: Paging Library Phần 2
Bài đăng này đã không được cập nhật trong 7 năm
Bài trước mình đã giới thiệu qua về Paging Library ( 1 component của Android Architecture Components) và áp dụng nó trong load dữ liệu từ Local. Hôm nay, mình sẽ tiếp tục giới thiệu với mọi người cách áp dụng Library Paging với Rest API.
1. Thêm component vào project
Android Architecture Component có sẵn trong Google’s Maven repository. Để sử dụng cần thực hiện các bước sau:
Open file build.grale
trong project thêm dòng dưới:
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
}
}
Add Architecture Components
Trong bài này mình sẽ sử dụng LiveData và ViewModel
Open build.gradle
trong module
project thêm các dependencies:
ext {
retrofitVersion = "2.2.0"
} 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 Paging
implementation 'android.arch.paging:runtime:1.0.0-alpha1'
//retrofit
compile "com.squareup.retrofit2:retrofit:${retrofitVersion}"
compile "com.squareup.retrofit2:converter-gson:${retrofitVersion}"
}
2. Setting up Retrofit for Pagination
Trong code sample, chúng ta sẽ sử làm việc với API bằng cách sử dụng thư viện: Retrofit và GSON. Chúng ta sẽ làm việc với GitHub API với các GitHub User endpoint
public interface GitHubService {
@GET("/users")
Call<List<User>> getUser(@Query("since") int since, @Query("per_page") int perPage);
} Tạo file RetrofitService.class
public class GitHubApi {
public static GitHubService createGitHubService() {
Retrofit.Builder builder = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://api.github.com");
return builder.build().create(GitHubService.class);
}
}
3. Create TiledDataSource
Sử dụng TiledDataSource class để xác định một nguồn dữ liệu. Nó sử dụng để load data gia tăng, được sử dụng trong paging danh sách. Bạn có thể tải các trang tùy ý dựa trên thông tin vị trí và có thể cung cấp số lượng cố định mỗi lần load dữ liệu. TiledDataSource hỗ trợ query các trang ở các vị trí tùy ý, vì vậy có thể cung cấp dữ liệu cho PagedLists theo thứ tự tùy ý.
Tạo class kế thừ TiledDataSource
public class TDataSource extends TiledDataSource<User> {
GitHubService gitHubService;
public TDataSource() {
gitHubService = GitHubApi.createGitHubService();
}
//Number of items that this DataSource can provide in total.
@Override
public int countItems() {
return DataSource.COUNT_UNDEFINED;
}
//Called to load items at from the specified position range.
@Override
public List<User> loadRange(int startPosition, int count) {
List<User> gitHubUser = new ArrayList();
try {
Response<List<User>> response = gitHubService.getUser(startPosition, count).execute();
if (response.isSuccessful() && response.code() == 200) {
gitHubUser.addAll(response.body());
} else {
Log.e("API CALL", response.message());
}
} catch (IOException e) {
e.printStackTrace();
}
return gitHubUser;
}
}
4. Create ViewModel
Trong ViewModel, chúng ta sẽ kế thừa từ Architecture Component ViewModel
, và làm việc với LiveData
of PagedList
public class UserViewModel extends ViewModel {
public LiveData<PagedList<User>> userList;
TDataSource tDataSource;
public UserViewModel() {
}
public void init(UserDao userDao) {
userList = new LivePagedListProvider<Integer, User>() {
@Override
protected DataSource<Integer, User> createDataSource() {
tDataSource = new TDataSource();
return tDataSource;
}
}.create(0, new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setPageSize(20)
.setInitialLoadSizeHint(20)
.build());
}
}
LivePagedListProvider: Nó được sử dụng để khởi tạo Database trả về LiveData
PagingList: PagedList là một List mà load data trong các trang từ DataSource
.Tất cả data trong một PagedList được load từ DataSource
của nó. Tạo một PagedList tải dữ liệu từ DataSource ngay lập tức, và vì lý do này, be done on a background thread. Các PagedList xây dựng sau đó có thể được chuyển đến và sử dụng trên thread UI. Điều này được thực hiện để ngăn chặn việc chuyển một danh sách không có nội dung tải đến chủ đề giao diện người dùng, mà thường không được trình bày cho người dùng.
5. Create Adapter
Để nói với PagedListAdapter
làm thế nào để phân biệt sự khác biệt giữa hai item, bạn sẽ cần phải implement new class, DiffCallback. Ở đây, bạn sẽ xác định hai điều.
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);
}
}
static class UserItemViewHolder extends RecyclerView.ViewHolder {
TextView userName, userId;
public UserItemViewHolder(View itemView) {
super(itemView);
userId = itemView.findViewById(R.id.userId);
userName = itemView.findViewById(R.id.userName);
}
public void bindTo(User user) {
userName.setText(user.firstName);
userId.setText(String.valueOf(user.userId));
}
}
}
6. Create RecyclerView
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);
All rights reserved