#android-layout #android-recyclerview #android-scrollview #android-nestedscrollview
#android-layout #android-recyclerview #android-scrollview #android-nestedscrollview
Вопрос:
Я пытаюсь удалить свой RecyclerView в фоновом потоке без каких-либо успехов.
Обновление RecyclerView по-прежнему блокирует основной поток.
Вот мой адаптер:
public class PostAdapter extends RecyclerView.Adapter<PostAdapter.PostViewHolder> {
private List<PostItems> postList;
private Context context;
private Queue<List<PostItems>> pendingUpdates = new ArrayDeque<>();
PostAdapter(List<PostItems> postList, Context context) {
this.postList = postList;
this.context = context;
}
@NonNull
@Override
public PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_view_wall_post, parent, false);
return new PostViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
PostItems post_items = postList.get(position);
...
...
.........
...
...
}
@Override
public int getItemCount() {
return postList.size();
}
@Override
public int getItemViewType(int position) {
return position;
}
static class PostViewHolder extends RecyclerView.ViewHolder {
PostViewHolder(@NonNull View itemView) {
super(itemView);
...
...
.........
...
...
}
}
}
/*
* here the background Thread
*
*/
// The Fragment or Activity will call this method
// when new data becomes available
public void updateItems(final List<PostItems> newItems) {
pendingUpdates.add(newItems);
if (pendingUpdates.size() > 1) {
return;
}
updateItemsInternal(newItems);
}
// This method does the heavy lifting of
// pushing the work to the background thread
void updateItemsInternal(final List<PostItems> newItems) {
final List<PostItems> oldItems = new ArrayList<>(this.postList);
final Handler handler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
final DiffUtil.DiffResult diffResult =
DiffUtil.calculateDiff(new DiffCb(oldItems, newItems));
handler.post(new Runnable() {
@Override
public void run() {
applyDiffResult(newItems, diffResult);
}
});
}
}).start();
}
// This method is called when the background work is done
protected void applyDiffResult(List<PostItems> newItems,
DiffUtil.DiffResult diffResult) {
pendingUpdates.remove();
dispatchUpdates(newItems, diffResult);
if (pendingUpdates.size() > 0) {
updateItemsInternal(pendingUpdates.peek());
}
}
// This method does the work of actually updating
// the backing data and notifying the adapter
protected void dispatchUpdates(List<PostItems> newItems,
DiffUtil.DiffResult diffResult) {
diffResult.dispatchUpdatesTo(this);
postList.clear();
postList.addAll(newItems);
Toast.makeText(context, "b" postList.size(), Toast.LENGTH_SHORT).show();
}
Вот мой класс DiffUtil:
class DiffCb extends DiffUtil.Callback {
private final List<PostItems> oldItems;
private final List<PostItems> newItems;
public DiffCb(List<PostItems> oldItems, List<PostItems> newItems) {
this.oldItems = oldItems;
this.newItems = newItems;
}
@Override
public int getOldListSize() {
return oldItems.size();
}
@Override
public int getNewListSize() {
return newItems.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldItems.get(oldItemPosition).equals(newItems.get(newItemPosition));
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldItems.get(oldItemPosition).equals(newItems.get(newItemPosition));
}
}
Обновление RecyclerView таким образом:
postList.addAll(response.body());
postAdapter.updateItems(homePostList);
Все работает нормально, когда мой RecyclerView не содержится в NestedScrollView или ScrollView.
Но когда мой RecyclerView содержится в NestedScrollView или ScrollView, обновление RecyclerView продолжает блокировать main thread
, как если бы DiffUtil был отключен.
Как предотвратить блокировку main thread
при обновлении RecyclerView, содержащегося в NestedScrollView или ScrollView?
Спасибо.
Ответ №1:
Старайтесь не создавать каждый раз новый адаптер, а вместо этого обновлять данные внутри адаптера. Также, если вы используете DiffUtils
, вы должны переопределить .equals
и .hashcode
в своем PostItems
классе, чтобы DIffUtils
знать, какой объект является новым, а какой объект уже существует.
Щелкните правой кнопкой мыши где-нибудь в своем PostItems
классе и выберите Generate
, затем выберите override equals and hashcode
, затем выберите уникальное поле в классе.
Также вы должны привязать представления
, например, в своем классе ViewHolder:
static class PostViewHolder extends RecyclerView.ViewHolder {
TextView tv1;
TextView tv2;
PostViewHolder(@NonNull View itemView) {
super(itemView);
tv1 = itemView.findViewById(R.id.tv1);
tv2 = itemView.findViewById(R.id.tv2);
}
}
Затем в .bindViewHolder
методе вы получаете доступ к своему представлению следующим образом:
@Override
public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
PostItems post_items = postList.get(position);
holder.tv1.setText(post_items.get_text_wall_post());
//etc
}
Основная идея состоит в том, чтобы не вызывать каждый раз .findViewById()
in .bindViewHolder
метод, потому что это достаточно медленно для RecyclerView
Комментарии:
1. Спасибо, но ваш ответ не имеет ничего полезного для моего вопроса.