gpt4 book ai didi

android - Recyclerview onCreateViewHolder 为每个项目调用

转载 作者:太空狗 更新时间:2023-10-29 15:58:43 33 4
gpt4 key购买 nike

我在 NestedScrollView 中有一个 RecyclerView,它显示一些异步下载的数据。问题是在初始化项目时存在明显的滞后。经过一些测试后,我发现问题是每个项目都会调用 onCreateViewHolder 并且需要一些时间来膨胀布局。这是我的适配器:

public class EpisodeAdapter extends RecyclerView.Adapter<EpisodeAdapter.ViewHolder> {

private static final String TAG = "EpisodeAdapter";

private static final int NO_POSITION = -1;
private static final int EXPAND = 1;
private static final int COLLAPSE = 2;

private SparseArray<Episode> episodes;
private OnItemClickListener<Episode> downloadClickListener;
private OnItemClickListener<Episode> playClickListener;

private RecyclerView recyclerView;
private final EpisodeAnimator episodeAnimator;
private final Transition expandCollapse;

private int expandedPosition = NO_POSITION;

public EpisodeAdapter() {
episodes = new SparseArray<>();
episodeAnimator = new EpisodeAnimator();
expandCollapse = new AutoTransition();
}

//Called when first loading items
public void swapEpisodes(SparseArray<Episode> newEpisodes){
final int previousSize = episodes.size();
episodes = newEpisodes;
expandedPosition = NO_POSITION;
Log.e(TAG, "Swap called");
if(previousSize == 0) {
notifyItemRangeInserted(0, episodes.size());
}
else {
notifyItemRangeChanged(0, Math.max(previousSize, episodes.size()));
}
}

//Called when downloading other information, this seems to work fine without delay
public void setEpisodesDetails(final List<TmdbEpisode> episodeList){
for (TmdbEpisode episode : episodeList){
final int position = episodes.indexOfKey(episode.getNumber());
notifyItemChanged(position, episode);
}
}

@Override
public EpisodeAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.e(TAG, "Start createViewHolder");
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_episode, parent, false);
ViewHolder viewHolder = new ViewHolder(view);

viewHolder.downloadButton.setOnClickListener(v -> {
if(downloadClickListener != null)
downloadClickListener.onItemClick(v, episodes.valueAt(viewHolder.getAdapterPosition()));
});

viewHolder.playButton.setOnClickListener(v -> {
if(playClickListener != null)
playClickListener.onItemClick(v, episodes.valueAt(viewHolder.getAdapterPosition()));
});

viewHolder.itemView.setOnClickListener(v -> {
final int position = viewHolder.getAdapterPosition();
if(position == NO_POSITION) return;

TransitionManager.beginDelayedTransition(recyclerView, expandCollapse);
episodeAnimator.setAnimateMoves(false);

//Collapse any currently expanded items
if(expandedPosition != NO_POSITION){
notifyItemChanged(expandedPosition, COLLAPSE);
}

//Expand clicked item
if(expandedPosition != position){
expandedPosition = position;
notifyItemChanged(position, EXPAND);
}
else {
expandedPosition = NO_POSITION;
}
});

Log.e(TAG, "Finish createViewHolder");
return viewHolder;
}

@Override
public void onBindViewHolder(EpisodeAdapter.ViewHolder holder, int itemPosition) {
Log.e(TAG, "Start");
holder.number.setText(String.valueOf(episodes.keyAt(itemPosition)));
holder.details.setVisibility(View.GONE);
holder.itemView.setActivated(false);
Log.e(TAG, "Finish");
}

@Override
public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
Log.e(TAG, "Start payloads");
if(payloads.contains(EXPAND) || payloads.contains(COLLAPSE)){
setExpanded(holder, position == expandedPosition);
}
else if(!payloads.isEmpty() && payloads.get(0) instanceof TmdbEpisode){
TmdbEpisode episode = (TmdbEpisode) payloads.get(0);
holder.title.setText(episode.getName());
holder.details.setText(episode.getOverview());
}
else {
onBindViewHolder(holder, position);
}
Log.e(TAG, "Finish payloads");
}

private void setExpanded(ViewHolder holder, boolean isExpanded) {
holder.itemView.setActivated(isExpanded);
holder.details.setVisibility((isExpanded) ? View.VISIBLE : View.GONE);
}


public void setPlayClickListener(OnItemClickListener<Episode> onItemClickListener){
playClickListener = onItemClickListener;
}

public void setDownloadClickListener(OnItemClickListener<Episode> onItemClickListener){
downloadClickListener = onItemClickListener;
}

@Override
public int getItemCount() {
return episodes.size();
}

static class ViewHolder extends RecyclerView.ViewHolder {

View itemView;
TextView number;
FadeTextSwitcher title;
ImageButton downloadButton;
FloatingActionButton playButton;
TextView details;

ViewHolder(View itemView) {
super(itemView);
Log.e(TAG, "Start constructor");
this.itemView = itemView;
number = itemView.findViewById(R.id.number);
title = itemView.findViewById(R.id.title);
downloadButton = itemView.findViewById(R.id.download_button);
playButton = itemView.findViewById(R.id.play_button);
details = itemView.findViewById(R.id.details);
Log.e(TAG, "Finish constructor");
}
}

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
this.recyclerView = recyclerView;
this.recyclerView.setItemAnimator(episodeAnimator);

expandCollapse.setDuration(recyclerView.getContext().getResources().getInteger(R.integer.episode_expand_collapse_duration));
expandCollapse.setInterpolator(AnimationUtils.loadInterpolator(this.recyclerView.getContext(), android.R.interpolator.fast_out_slow_in));
expandCollapse.addListener(new Transition.TransitionListener() {
@Override
public void onTransitionStart(android.transition.Transition transition) {
EpisodeAdapter.this.recyclerView.setOnTouchListener((v, event) -> true);
}

@Override
public void onTransitionEnd(android.transition.Transition transition) {
episodeAnimator.setAnimateMoves(true);
EpisodeAdapter.this.recyclerView.setOnTouchListener(null);
}

@Override
public void onTransitionCancel(android.transition.Transition transition) {}

@Override
public void onTransitionPause(android.transition.Transition transition) {}

@Override
public void onTransitionResume(android.transition.Transition transition) {}
});
}

static class EpisodeAnimator extends SlideInItemAnimator {
private boolean animateMoves = false;

EpisodeAnimator() {
super();
}

void setAnimateMoves(boolean animateMoves) {
this.animateMoves = animateMoves;
}

@Override
public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
if (!animateMoves) {
dispatchMoveFinished(holder);
return false;
}
return super.animateMove(holder, fromX, fromY, toX, toY);
}
}
}

有没有办法强制为每个项目重复使用相同的 ViewHolder?所以 onCreateViewHolder 将被调用一次。

我还在 recyclerview 中设置了 nestedScrollingEnabled="false"

最佳答案

I have a RecyclerView inside a NestedScrollView

我猜你的 <RecyclerView>标签的高度定义为 wrap_content .如果是,则意味着您正在为数据集中的每个项目扩充布局资源(并创建一个 ViewHolder 对象);可能有数以千计的布局膨胀和对象创建。

RecyclerView的回收行为|仅当 recyclerview 的高度小于显示其子项所需的高度时才有效。 recyclerview 创建一个小的两位数 ViewHolder 是正常的实例(通常您可以同时在屏幕上看到许多项目,再加上一些以优化屏幕外的 View ),但这取决于您的 recyclerview 的大小受屏幕大小限制的事实(即您正在使用 match_parent或固定尺寸)。

如果是 RecyclerViewwrap_content NestedScrollView 内的高度,用户将无法一次查看所有项目,但 Android 框架只知道您有一个足够大的回收 View 来容纳数据集中的每个项目,因此它必须为每个项目创建一个 viewholder。

您必须找到一种方法来重新设计您的布局层次结构,以便您可以为您的 RecyclerView 使用一些有限的高度。 .

关于android - Recyclerview onCreateViewHolder 为每个项目调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48843786/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com