java - Android Stop recycler-View 适配器绑定数据已显示的项目
问题描述
我有一个应用程序使用 recyclerView 来显示来自 Google Books API 的结果。
在每一个onBindViewHolder
中,我要求客户给我数据,这最终导致我超过速率限制,因为每次滚动都会调用数据。
假设我得到了位置 1-5 的数据,我向下滚动到位置 6-10,然后返回到 1-5。我如何确保它不会再次为位置 1-5 调用客户端,因为它已经加载了它们?
我只希望它已经调用的任何东西都留在那里。
我的适配器看起来像这样(我删除了一些像更多视图这样的部分,所以它不会混淆):
public class MyBooksAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<DiscoverBooks> discoverBooks;
private FirebaseFirestore db;
private FirebaseAuth auth;
private String UID, BookID2;
private int count, gbsSize, counter;
interface OnDiscoverBookClickListener {
void onClick(DiscoverBooks discoverBooks);
}
private OnDiscoverBookClickListener listener;
public MyBooksAdapter(int counter, List<DiscoverBooks> discoverBooks, int gbsSize, OnDiscoverBookClickListener listener) {
this.counter = counter;
this.discoverBooks = discoverBooks;
this.listener = listener;
this.gbsSize = gbsSize;
}
@Override
public int getItemViewType(int position) {
return AppConstants.IS_NOT_ADS_POSITION;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
View view;
view = LayoutInflater.from( viewGroup.getContext() ).inflate( R.layout.item_book_mybook, viewGroup, false );
return new DiscoverBooksViewHolder( view );
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
holder.setIsRecyclable( false );
if (holder instanceof DiscoverBooksViewHolder) {
((MyBooksAdapter.DiscoverBooksViewHolder) holder).bind( (discoverBooks.get( position )), holder );
}
}
@Override
public int getItemCount() {
return discoverBooks.size();
}
class DiscoverBooksViewHolder extends RecyclerView.ViewHolder {
private Button tv_Link;
private CardView cardView;
private ImageView Iv_BookCover;
private TextView tv_Author, tv_BorrowedTo, tv_BorrowedTill, tv_DateAdded, tv_Title;
private ImageButton ib_Options;
private ToggleButton tb_Status;
private DiscoverBooks discoverBooks;
private DiscoverBooksViewHolder(View itemView) {
super( itemView );
cardView = itemView.findViewById( R.id.imagecard );
Iv_BookCover = itemView.findViewById( R.id.iv_BookCover );
tv_Title = itemView.findViewById( R.id.tv_Title );
tv_Author = itemView.findViewById( R.id.tv_Author );
tv_DateAdded = itemView.findViewById( R.id.tv_DateAdded );
tv_BorrowedTo = itemView.findViewById( R.id.tv_BorrowedTo );
tv_BorrowedTill = itemView.findViewById( R.id.tv_BorrowedTill );
tv_Link = itemView.findViewById( R.id.tv_Link );
ib_Options = itemView.findViewById( R.id.ib_Options );
tb_Status = itemView.findViewById( R.id.tb_Status );
}
private void bind(DiscoverBooks discoverBooks, RecyclerView.ViewHolder viewHolder) {
this.discoverBooks = discoverBooks;
db = FirebaseFirestore.getInstance();
auth = FirebaseAuth.getInstance();
String BookID = discoverBooks.getBookID();
if (BookID.length() > AppConstants.UPLOADED_BOOK_LENGTH) {
db.collection( "Books" ).document( BookID ).get()
.addOnCompleteListener( task -> {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
DO SOMETHING
}
}
} );
} else {
//HERE I CALL GOOGLE BOOKS API
MyBookClient.getInstance().getBooks( BookID, new JsonHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
if (response != null) {
final MyBook books = MyBook.fromJson( response );
//DO SOMETHING
}
}
} );
}
}
}
}
解决方案
好的,我明白你的问题了。对于每个 bookID,您从 Google 图书中获取其数据,现在您不想为已加载的项目点击 api。
ArrayList
简单地说,为as创建一个全局变量
private ArrayList<MyBook> mybooks = new ArrayList();
打电话onBind()
给onBindViewHolder()
你
((MyBooksAdapter.DiscoverBooksViewHolder) holder).bind(position, discoverBooks.get( position), holder);
用这个替换你onBind()
的:
private void bind(int position, UserData discoverBooks, RecyclerView.ViewHolder viewHolder) {
this.discoverBooks = discoverBooks;
db = FirebaseFirestore.getInstance();
auth = FirebaseAuth.getInstance();
String BookID = discoverBooks.getBookID();
if (BookID.length() > AppConstants.UPLOADED_BOOK_LENGTH) {
db.collection("Books").document(BookID).get()
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
DO SOMETHING
}
}
});
} else {
if (position >= myBooks.size() || myBooks.get(position) == null) {
//If the value doesn't exist in the ArrayList,
//it will hit the Google Books API
MyBookClient.getInstance().getBooks(BookID, new JsonHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
if (response != null) {
final MyBook books = MyBook.fromJson(response);
myBooks.add(position, books);
//DO SOMETHING
}
}
});
} else {
//If the value has already been loaded in the list,
//directly use it without hitting the API
final MyBook books = myBooks.get(position);
//DO SOMETHING
}
}
}
这将解决您的问题,它将存储已经从 API 访问的书籍,并且不会再次访问 API,并将使用列表来访问它们。
除此之外,我建议使用ViewBinding
它将整个替换DiscoverBooksViewHolder
为单行(在 Kotlin 中)或 2-3 行(在 Java 中),使用 viewBinding,您不必声明和初始化视图和视图可以直接使用 访问Binding
,然后您可以将 onBind() 从ViewHolder
.
推荐阅读
- flutter - 等待请求时如何在列表视图末尾添加 CircularProgressIndicator
- typescript - 如何验证方法中的数据并明确功能?
- python - 检测我的鼠标何时在 2 rect 上并选择操作
- php - Laravel 租赁包中的会话范围
- php - 如何获取不同存储库的图像?[错字3]
- jquery - 使用 JQuery 从 JSON 文件中提取值
- android - ML-KIT 是否包含视觉相机文本识别 API?
- python - OpenCV VideoWriter 是否使用 FFmpeg?它如何处理压缩或其他选项?
- vue.js - 将 URL 的最后一部分传递到挂载的钩子中
- ruby-on-rails - Ruby on Rails 表单中的枚举选择映射值