问题
What I Want: I want to implement Android Paging Library with network call only.
What I Understood: So, DataSource has three classes that I can extend.
- PageKeyedDataSource: If your web service has pageNumber in url then you can use it.
- ItemKeyedDataSource: When you are fetching nested data then you can use it. For example getting replies on particular comment.
- PositionalDataSource: You can use when you know exact number of data is going to load.
What I Tried : Code is below.
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
final GitHubUserAdapter gitHubUserAdapter = new GitHubUserAdapter();
GitHubUserViewModel gitHubUserViewModel = ViewModelProviders.of(this).get(GitHubUserViewModel.class);
gitHubUserViewModel.getLivePagedListData().observe(this, new Observer<PagedList<GitHubUserModel>>() {
@Override
public void onChanged(@Nullable PagedList<GitHubUserModel> gitHubUserModels) {
gitHubUserAdapter.submitList(gitHubUserModels);
}
});
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(gitHubUserAdapter);
}
}
GitHubUserAdapter.java
public class GitHubUserAdapter extends PagedListAdapter<GitHubUserModel, GitHubUserAdapter.GitHubUserViewHolder> {
public GitHubUserAdapter() {
super(DIFF_CALLBACK);
}
@NonNull
@Override
public GitHubUserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_github_user, parent, false);
return new GitHubUserViewHolder(layoutView);
}
@Override
public void onBindViewHolder(@NonNull GitHubUserViewHolder holder, int position) {
holder.tv_user_id.setText(String.valueOf(getItem(position).getId()));
}
class GitHubUserViewHolder extends RecyclerView.ViewHolder {
TextView tv_user_id;
public GitHubUserViewHolder(View itemView) {
super(itemView);
tv_user_id = itemView.findViewById(R.id.tv_user_id);
}
}
}
GitHubUserModel.java
public class GitHubUserModel {
private String id;
/*
Other response variables like avatar_url
*/
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
/*
Other getter setters for other variables like getAvatar_url() & setAvatar_url()
*/
public static DiffUtil.ItemCallback<GitHubUserModel> DIFF_CALLBACK = new DiffUtil.ItemCallback<GitHubUserModel>() {
@Override
public boolean areItemsTheSame(GitHubUserModel oldItem, GitHubUserModel newItem) {
return oldItem.id.equalsIgnoreCase(newItem.id);
}
@Override
public boolean areContentsTheSame(GitHubUserModel oldItem, GitHubUserModel newItem) {
return oldItem.equals(newItem);
}
};
}
GitHubUserViewModel.java
public class GitHubUserViewModel extends ViewModel {
private Executor mBackgroundThread;
private LiveData<PagedList<GitHubUserModel>> mGitHubListLiveData;
private APIEndPoints mApiEndPoints = RetrofitClient.getInstance().create(APIEndPoints.class);
public GitHubUserViewModel() {
mBackgroundThread = Executors.newFixedThreadPool(5);
getDataFromAPI();
}
private void getDataFromAPI() {
DataSource.Factory<Integer, GitHubUserModel> dataSourceFactory = new DataSource.Factory<Integer, GitHubUserModel>() {
@Override
public DataSource<Integer, GitHubUserModel> create() {
GitHubUserDataSource gitHubUserDataSource = new GitHubUserDataSource(mApiEndPoints);
return gitHubUserDataSource;
}
};
PagedList.Config pagedListConfig = new PagedList.Config.Builder()
.setPageSize(6)
.setPrefetchDistance(3)
.setInitialLoadSizeHint(6)
.setEnablePlaceholders(true)
.build();
mGitHubListLiveData = new LivePagedListBuilder<>(dataSourceFactory, pagedListConfig)
.setInitialLoadKey(0)
.setFetchExecutor(mBackgroundThread)
.build();
}
public LiveData<PagedList<GitHubUserModel>> getLivePagedListData() {
return mGitHubListLiveData;
}
}
GitHubUserDataSource.java
public class GitHubUserDataSource extends ItemKeyedDataSource<Integer, GitHubUserModel> {
private final APIEndPoints mApiEndPoints;
GitHubUserDataSource(APIEndPoints apiEndPoints) {
this.mApiEndPoints = apiEndPoints;
}
int inRange(int position, int start, int end) {
if (position < start) return start;
if (position > end) return end;
return position;
}
@NonNull
@Override
public Integer getKey(@NonNull GitHubUserModel gitHubUserModel) {
return Integer.valueOf(gitHubUserModel.getId());
}
@Override
public void loadInitial(@NonNull final LoadInitialParams<Integer> params, @NonNull final LoadInitialCallback<GitHubUserModel> callback) {
mApiEndPoints.getGitHubUsers().subscribe(new Observer<List<GitHubUserModel>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(List<GitHubUserModel> gitHubUserModels) {
int pageSize = Math.min(8, params.requestedLoadSize);
int firstItem = inRange(params.requestedInitialKey == null ? 0 : params.requestedInitialKey,
0, gitHubUserModels.size());
int lastItem = inRange(firstItem + pageSize, 0, gitHubUserModels.size());
List<GitHubUserModel> gitHubUserModelsToPass;
if (firstItem == lastItem) {
gitHubUserModelsToPass = new ArrayList<>();
} else {
gitHubUserModelsToPass = gitHubUserModels.subList(firstItem, lastItem);
}
if (params.placeholdersEnabled) {
callback.onResult(gitHubUserModelsToPass, firstItem, gitHubUserModels.size());
} else {
callback.onResult(gitHubUserModelsToPass);
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
@Override
public void loadAfter(@NonNull final LoadParams<Integer> params, @NonNull final LoadCallback<GitHubUserModel> callback) {
mApiEndPoints.getGitHubUsers().subscribe(new Observer<List<GitHubUserModel>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(List<GitHubUserModel> gitHubUserModels) {
int pageSize = Math.min(20, params.requestedLoadSize);
int firstItem = inRange(params.key + 1, 0, gitHubUserModels.size());
int lastItem = inRange(firstItem + pageSize, 0, gitHubUserModels.size());
List<GitHubUserModel> gitHubUserModelsToPass;
if (firstItem == lastItem) {
gitHubUserModelsToPass = new ArrayList<>();
} else {
gitHubUserModelsToPass = gitHubUserModels.subList(firstItem, lastItem);
}
callback.onResult(gitHubUserModelsToPass);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
@Override
public void loadBefore(@NonNull final LoadParams<Integer> params, @NonNull final LoadCallback<GitHubUserModel> callback) {
mApiEndPoints.getGitHubUsers().subscribe(new Observer<List<GitHubUserModel>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(List<GitHubUserModel> gitHubUserModels) {
int pageSize = Math.min(20, params.requestedLoadSize);
int lastItem = inRange(params.key - 1, 0, gitHubUserModels.size());
int firstItem = inRange(lastItem - pageSize, 0, gitHubUserModels.size());
List<GitHubUserModel> gitHubUserModelsToPass;
if (firstItem == lastItem) {
gitHubUserModelsToPass = new ArrayList<>();
} else {
gitHubUserModelsToPass = gitHubUserModels.subList(firstItem, lastItem);
}
callback.onResult(gitHubUserModelsToPass);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
}
Logcat
Process: com.happyemi.paginglibdemo, PID: 8464
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.happyemi.paginglibdemo.GitHubUserModel.getId()' on a null object reference
at com.happyemi.paginglibdemo.GitHubUserAdapter.onBindViewHolder(GitHubUserAdapter.java:37)
at com.happyemi.paginglibdemo.GitHubUserAdapter.onBindViewHolder(GitHubUserAdapter.java:14)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6673)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6714)
at android.support.v7.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5647)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5913)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5752)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5748)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2232)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1559)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1519)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:614)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3812)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3529)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:4082)
at android.view.View.layout(View.java:16969)
at android.view.ViewGroup.layout(ViewGroup.java:5583)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1189)
at android.view.View.layout(View.java:16969)
at android.view.ViewGroup.layout(ViewGroup.java:5583)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:396)
at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
at android.view.View.layout(View.java:16969)
at android.view.ViewGroup.layout(ViewGroup.java:5583)
at android.support.v7.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:443)
at android.view.View.layout(View.java:16969)
at android.view.ViewGroup.layout(ViewGroup.java:5583)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:396)
at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
at android.view.View.layout(View.java:16969)
at android.view.ViewGroup.layout(ViewGroup.java:5583)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:2001)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1844)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1753)
at android.view.View.layout(View.java:16969)
at android.view.ViewGroup.layout(ViewGroup.java:5583)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:396)
at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
at com.android.internal.policy.PhoneWindow$DecorView.onLayout(PhoneWindow.java:2728)
at android.view.View.layout(View.java:16969)
at android.view.ViewGroup.layout(ViewGroup.java:5583)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2552)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2255)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1321)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6708)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894)
at android.view.Choreographer.doCallbacks(Choreographer.java:696)
at android.view.Choreographer.doFrame(Choreographer.java:631)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880)
at android.os.Handler.handleCallback(Handler.java:822)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5811)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$
I have tried with all three DataSource classes (PageKeyedDataSource, ItemKeyedDataSource, PositionalDataSource) but not getting what I'm missing.
Any help will be appreciated.
回答1:
Actually you forgot to post the value inside DataSource.Factory().
Inside GitHubUserViewModel.java class change your DataSource.Factory method code to :
DataSource.Factory<Integer, GitHubUserModel> dataSourceFactory = new DataSource.Factory<Integer, GitHubUserModel>() {
@Override
public DataSource<Integer, GitHubUserModel> create() {
GitHubUserDataSource gitHubUserDataSource = new GitHubUserDataSource(mApiEndPoints);
mGitHubLiveData.postValue(gitHubUserDataSource); // add this line.
return gitHubUserDataSource;
}
};
Read more about postValue() method here - MutableLiveData.
来源:https://stackoverflow.com/questions/51999197/android-paging-library-which-datasource-i-should-use