【问题标题】:RecyclerView stutters when new view added添加新视图时 RecyclerView 口吃
【发布时间】:2016-08-23 10:00:45
【问题描述】:

我有一个从 API 动态填充的回收器视图。回收器视图项包含一个图像视图,其顶部有分层的文本,图像视图的图像来自 API,并使用 Picasso 加载。滚动 recyclerview 时,我发现当一个新视图添加到底部时,滚动中会出现轻微的卡顿。我还发现滚动的次数越多,滚动的速度越慢,响应速度越慢。我已经尝试将它与注释掉的毕加索代码一起使用并得到相同的结果。

这是我的 recyclerview 适配器:

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

Context context;
public ArrayList<EventObject> eventList;
private LayoutInflater mInflater;
private String category;

public static class ViewHolder extends RecyclerView.ViewHolder {
    private ImageView img_main;
    private RelativeLayout layoutItem;
    private TextView txt_event_name;
    private TextView txt_event_details;
    private TextView txt_going_to;

    public ViewHolder(View itemView) {
        super(itemView);
        img_main = (ImageView) itemView.findViewById(R.id.img_main);
        txt_event_details = (TextView) itemView.findViewById(R.id.txt_event_details);
        txt_event_name = (TextView) itemView.findViewById(R.id.txt_event_name);
        txt_going_to = (TextView) itemView.findViewById(R.id.txt_going_to);
        gradient_view = itemView.findViewById(R.id.gradient_view);
        layoutItem = (RelativeLayout) itemView.findViewById(R.id.rl_event_item);
    }

    public void bindView(final Context context, final EventObject eventObject, String category) throws JSONException, ParseException {
        txt_event_name.setTypeface(FontClass.getOpenSansRegular(context));
        txt_event_details.setTypeface(FontClass.getOpenSansLight(context));
        txt_going_to.setTypeface(FontClass.getOpenSansLight(context));

        txt_event_name.setText(eventObject.getEventName());

        if (eventObject.getVenueName().contains(eventObject.getTown())) {
            txt_event_details.setText(eventObject.getVenueName() + ", " + getFormattedDate(eventObject.getEventDate()));
        } else {
            txt_event_details.setText(eventObject.getVenueName() + ", " + eventObject.getTown() + ", " + getFormattedDate(eventObject.getEventDate()));
        }

        if(eventObject.getFeeFreeStatus() == 1){
            if(category.equalsIgnoreCase("no fees")) {
                txt_going_to.setVisibility(View.GONE);
            } else {
                txt_going_to.setVisibility(View.VISIBLE);
                txt_going_to.setText("Fee free tickets available");
            }

        } else if (Integer.parseInt(eventObject.getGoingToCount()) >= 200) {
            txt_going_to.setVisibility(View.VISIBLE);
            txt_going_to.setText("Popular event: " + eventObject.getGoingToCount() + " going");
        } else {
            txt_going_to.setVisibility(View.GONE);
        }


        layoutItem.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ((HomeActivity) context).setEventProfileFrag(eventObject.getFullJsonObject(), null);
            }
        });

        Picasso.with(context)
                .load(eventObject.getImageUrl())
                .placeholder(R.drawable.holder_image)
                .into(img_main);

    }

    private String getFormattedDate(String dateString) throws ParseException {

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.UK);
        Date newDate = format.parse(dateString);

        format = new SimpleDateFormat("EEEE dd MMMM", Locale.UK);
        String date = format.format(newDate);

        return date;
    }

}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_event_list_item, parent, false);
    return new ViewHolder(itemView);
}

@Override
public void onBindViewHolder(final ViewHolder holder, int position) {

    try {
        holder.bindView(context, eventList.get(position), this.category);
    } catch (JSONException e) {
        e.printStackTrace();
    } catch (ParseException e) {
        e.printStackTrace();
    }
}

@Override
public long getItemId(int position) {
    return position;
}

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


public EventListAdapter(Context context, ArrayList<EventObject> eventList, String category) {
    this.context = context;
    this.eventList = eventList;
    this.category = category;
    mInflater = LayoutInflater.from(context);
    setHasStableIds(true);
}

public void addItems(ArrayList<EventObject> eventList) {
    this.eventList.addAll(eventList);
    notifyDataSetChanged();
}
}

【问题讨论】:

  • 尝试不使用 setTypeface 会获得更多时间
  • 这很正常,取决于原始缩略图和设备电源的大小。您可以通过将缩略图的大小即时调整为 ItemImageView futurestud.io/blog/picasso-image-resizing-scaling-and-fit 上的确切大小来加快速度。您能否确认当您向下滚动时加载项目然后向上滚动列表感觉更快、更流畅?这是因为毕加索从缓存而不是互联网加载拇指
  • 在 Q 中添加你正在为你的项目充气的布局。这也可能是一个问题

标签: android android-recyclerview


【解决方案1】:

您可能会遇到口吃的原因:

  1. 您(可能)正在反序列化适配器内的数据。你不应该,反序列化可能是一个昂贵的过程。摆脱 onBindViewHolder 内部的反序列化,发送反序列化的模型对象。

try {
        holder.bindView(context, eventList.get(position), this.category);
    } catch (JSONException e) {
        e.printStackTrace();
    } catch (ParseException e) {
        e.printStackTrace();
    } 
  1. 不要强制 RecyclerView.Adapter 在不需要时尝试重绘所有项目。改进这一点并使用notifyItemXXXX()notifyItemRangeXXX() 方法:

public void addItems(ArrayList eventList) {
    this.eventList.addAll(eventList);
    notifyDataSetChanged();
}
  1. 在反序列化数据时解析日期和原语(但不在 onBindViewHolder() 反序列化内部)

  2. 尝试以不同的方式设置字体,例如在您的 xml 中提供它。缓存字体。

  3. .contains() 对于长字符串可能会很慢

【讨论】:

  • 能否举个例子说明如何改进问题中的代码?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-19
  • 1970-01-01
  • 2020-08-01
  • 1970-01-01
相关资源
最近更新 更多