由于 ViewModel 的项目计数错误,RecyclerView 无法滚动
RecyclerView cannot be scrolled because of wrong item count from ViewModel
我正在开发一个简单的应用程序来搜索 github 用户(利用 Github API)。不幸的是,请求 return 多个项目将默认分页为 30 个项目。所以你必须在你自己的分页机制上工作。
这是我的简单逻辑:
TOTAL_PAGES = ceil(total_count/30)
if (currentPage < TOTAL_PAGES) {
currentPage++;
doSearchUser(who, currentPage);
}
例如你搜索用户goreng
https://api.github.com/search/users?q=goreng
它产生total_count = 33,这意味着我们的TOTAL_PAGES是2。
以及一些相关代码:
MainActivity.java
private void doSearchUser(String who, int pageNum) {
totalCount = viewModel.getTotalCount();
viewModel.setSearchResult(who, pageNum);
viewModel.getSearchResult().observe(this, new Observer<ArrayList<User>>() {
@Override
public void onChanged(ArrayList<User> theList) {
searchAdapter = new SearchAdapter(context, theList);
recyclerView.setAdapter(searchAdapter);
}
});
totalCount = viewModel.getTotalCount(); // not working. always returns 0 :(
TOTAL_PAGES = ((int)Math.ceil((double) totalCount/(double)30));
}
private void setUpRecyclerView() {
recyclerView = findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
List<User> userList = new ArrayList<User>();
searchAdapter = new SearchAdapter(context, userList) ;
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(searchAdapter);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if(!recyclerView.canScrollVertically(1) && dy != 0) {
if (currentPage < TOTAL_PAGES) {
currentPage++;
doSearchUser(who, currentPage);
}
}
}
});
}
UserViewModel.java
package com.divbyzero.app.githubusersearch.viewmodel;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.divbyzero.app.githubusersearch.api.APIEndPoint;
import com.divbyzero.app.githubusersearch.api.APIService;
import com.divbyzero.app.githubusersearch.response.SearchResponse;
import com.divbyzero.app.githubusersearch.model.User;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class UserViewModel extends ViewModel {
private MutableLiveData<ArrayList<User>> mutableLiveData = new MutableLiveData<>();
private int totalCount;
private ArrayList<User> savedData = new ArrayList<User>();
public void setSearchResult(String who, int page){
Retrofit retrofit = APIService.getRetrofitService();
APIEndPoint apiEndpoint = retrofit.create(APIEndPoint.class);
Call<SearchResponse> call = apiEndpoint.getSearchResult(who, page);
call.enqueue(new Callback<SearchResponse>() {
@Override
public void onResponse(Call<SearchResponse> call, Response<SearchResponse> response) {
if (response.body() != null) {
savedData.addAll(response.body().getItems());
//mutableLiveData.setValue((ArrayList<User>) response.body().getItems());
mutableLiveData.setValue(savedData);
totalCount = response.body().getTotalCount();
Log.d("DBG", "OK");
}
}
@Override
public void onFailure(Call<SearchResponse> call, Throwable t) {
Log.d("DBG", "Failed: "+t.getMessage());
}
});
}
public LiveData<ArrayList<User>> getSearchResult(){
return mutableLiveData;
}
public void clear(){
savedData.clear();
mutableLiveData.setValue(new ArrayList<User>());
}
public int getTotalCount(){
return totalCount;
}
}
完整回购:https://github.com/anta40/GithubUserSearch
我的问题是 viewModel.getTotalCount()
最初 returns 0(而对于上面的 URL,它应该 return 33)。不过,这需要一段时间,最终会 return 33。这就是为什么我无法滚动查看更多项目。如何解决这个问题?
当你开始时你做 viewModel.setSearchResult(who, pageNum);
那是异步 api 调用。您的代码不等待结果并继续前进,然后您注册观察者。然后您尝试获取总计数,但 api 调用尚未完成。这就是你得到 0 的原因。你需要等待 api 调用完成。当你的实时数据有新项目时它就会完成,对吧?这就是为什么在方法 onChanged
中你将有 totalCount = 33
尝试这样做
viewModel.getSearchResult().observe(this, new Observer<ArrayList<User>>() {
@Override
public void onChanged(ArrayList<User> theList) {
totalCount = viewModel.getTotalCount();
TOTAL_PAGES = ((int)Math.ceil((double) totalCount/(double)30));
searchAdapter = new SearchAdapter(context, theList);
recyclerView.setAdapter(searchAdapter);
}
});
我正在开发一个简单的应用程序来搜索 github 用户(利用 Github API)。不幸的是,请求 return 多个项目将默认分页为 30 个项目。所以你必须在你自己的分页机制上工作。
这是我的简单逻辑:
TOTAL_PAGES = ceil(total_count/30)
if (currentPage < TOTAL_PAGES) {
currentPage++;
doSearchUser(who, currentPage);
}
例如你搜索用户goreng
https://api.github.com/search/users?q=goreng
它产生total_count = 33,这意味着我们的TOTAL_PAGES是2。
以及一些相关代码:
MainActivity.java
private void doSearchUser(String who, int pageNum) {
totalCount = viewModel.getTotalCount();
viewModel.setSearchResult(who, pageNum);
viewModel.getSearchResult().observe(this, new Observer<ArrayList<User>>() {
@Override
public void onChanged(ArrayList<User> theList) {
searchAdapter = new SearchAdapter(context, theList);
recyclerView.setAdapter(searchAdapter);
}
});
totalCount = viewModel.getTotalCount(); // not working. always returns 0 :(
TOTAL_PAGES = ((int)Math.ceil((double) totalCount/(double)30));
}
private void setUpRecyclerView() {
recyclerView = findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
List<User> userList = new ArrayList<User>();
searchAdapter = new SearchAdapter(context, userList) ;
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(searchAdapter);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if(!recyclerView.canScrollVertically(1) && dy != 0) {
if (currentPage < TOTAL_PAGES) {
currentPage++;
doSearchUser(who, currentPage);
}
}
}
});
}
UserViewModel.java
package com.divbyzero.app.githubusersearch.viewmodel;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.divbyzero.app.githubusersearch.api.APIEndPoint;
import com.divbyzero.app.githubusersearch.api.APIService;
import com.divbyzero.app.githubusersearch.response.SearchResponse;
import com.divbyzero.app.githubusersearch.model.User;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class UserViewModel extends ViewModel {
private MutableLiveData<ArrayList<User>> mutableLiveData = new MutableLiveData<>();
private int totalCount;
private ArrayList<User> savedData = new ArrayList<User>();
public void setSearchResult(String who, int page){
Retrofit retrofit = APIService.getRetrofitService();
APIEndPoint apiEndpoint = retrofit.create(APIEndPoint.class);
Call<SearchResponse> call = apiEndpoint.getSearchResult(who, page);
call.enqueue(new Callback<SearchResponse>() {
@Override
public void onResponse(Call<SearchResponse> call, Response<SearchResponse> response) {
if (response.body() != null) {
savedData.addAll(response.body().getItems());
//mutableLiveData.setValue((ArrayList<User>) response.body().getItems());
mutableLiveData.setValue(savedData);
totalCount = response.body().getTotalCount();
Log.d("DBG", "OK");
}
}
@Override
public void onFailure(Call<SearchResponse> call, Throwable t) {
Log.d("DBG", "Failed: "+t.getMessage());
}
});
}
public LiveData<ArrayList<User>> getSearchResult(){
return mutableLiveData;
}
public void clear(){
savedData.clear();
mutableLiveData.setValue(new ArrayList<User>());
}
public int getTotalCount(){
return totalCount;
}
}
完整回购:https://github.com/anta40/GithubUserSearch
我的问题是 viewModel.getTotalCount()
最初 returns 0(而对于上面的 URL,它应该 return 33)。不过,这需要一段时间,最终会 return 33。这就是为什么我无法滚动查看更多项目。如何解决这个问题?
当你开始时你做 viewModel.setSearchResult(who, pageNum);
那是异步 api 调用。您的代码不等待结果并继续前进,然后您注册观察者。然后您尝试获取总计数,但 api 调用尚未完成。这就是你得到 0 的原因。你需要等待 api 调用完成。当你的实时数据有新项目时它就会完成,对吧?这就是为什么在方法 onChanged
中你将有 totalCount = 33
尝试这样做
viewModel.getSearchResult().observe(this, new Observer<ArrayList<User>>() {
@Override
public void onChanged(ArrayList<User> theList) {
totalCount = viewModel.getTotalCount();
TOTAL_PAGES = ((int)Math.ceil((double) totalCount/(double)30));
searchAdapter = new SearchAdapter(context, theList);
recyclerView.setAdapter(searchAdapter);
}
});