Android Architecture Components: Paging Library Phần 2
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. Android Architecture Component có sẵn trong ...
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.
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' } }
}
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}"
}
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); }
}
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; }
}
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.
Để 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)); } }
}
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);
Dowload project