【问题标题】:Weird RecyclerView and ListView behavior [duplicate]奇怪的 RecyclerView 和 ListView 行为[重复]
【发布时间】:2018-02-10 18:16:51
【问题描述】:

首先对不起我的英语不好。

RecyclerView 有问题。我有一个带有EditText、提交按钮和RecyclerView 的布局。

我可以在EditText 中输入一些文本,然后单击提交,文本将添加到RecyclerView。问题是如果有很多消息,那么RecyclerView 就会发疯。它停止显示正确的消息,它弄乱了消息的顺序等等。

如果我设置 holder.setIsRecyclable(false); 一切似乎都可以正常工作,但在我看来这是一个糟糕的解决方案。

对于单个项目的布局,我使用自定义LinearLayout 视图,这可能会导致这里出现问题,但我不确定。

如何在RecyclerView上敲诈以保持添加项目的正确顺序?

这是我的RecyclerView 的适配器。

public class MessagesAdapter extends RecyclerView.Adapter<MessagesAdapter.RecyclerViewHolder> {

    private List<String> messagesList = new LinkedList<>();

    public MessagesAdapter() {
        for (int i = 0; i < 13; ++i) {
            messagesList.add(String.valueOf(i));
        }
    }

    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new RecyclerViewHolder(LayoutInflater.from(parent.getContext())
                .inflate(R.layout.message_list_item, parent, false));
    }

    @Override
    public void onBindViewHolder(RecyclerViewHolder holder, int position) {
        String message = messagesList.get(position);
        holder.mHeartBeatMessage.setText(message);
        // holder.setIsRecyclable(false);
    }

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

    void addItem(String message) {
        this.messagesList.add(message);
    }

    static class RecyclerViewHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.heartBeatMessage)
        protected HeartBeat mHeartBeatMessage;

        RecyclerViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, view);
        }
    }
}

我发现我的自定义视图会产生问题。我可能以一种糟糕的方式过度劳累。

这是我在适配器中保存的自定义视图。

public class HeartBeat extends LinearLayout {
String mText = "";

public HeartBeat(Context context) {
    super(context);
}

public HeartBeat(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs);
}

public HeartBeat(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs);
}

/**
 * Initialize main variables.
 */
private void init(Context context, @Nullable AttributeSet attrs) {
    if (attrs != null) {
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.HeartBeat,
                0, 0);

        try {
            mText = a.getString(R.styleable.HeartBeat_text);
        } finally {
            a.recycle();
        }
    }

    ImageView heartBeat = new ImageView(context);
    heartBeat.setBackgroundResource(R.drawable.bg_chat_heartbeat);
    heartBeat.setImageResource(R.drawable.heartbeat);
    ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(0, 0);
    layoutParams.width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources().getDisplayMetrics());
    layoutParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics());
    heartBeat.setLayoutParams(layoutParams);
    addView(heartBeat);

    Drawable drawable = heartBeat.getDrawable();
    if (drawable instanceof AnimatedVectorDrawableCompat) {
        ((AnimatedVectorDrawableCompat) drawable).registerAnimationCallback(new Animatable2Compat.AnimationCallback() {
            @Override
            public void onAnimationEnd(Drawable drawable) {
                super.onAnimationEnd(drawable);
                HeartBeat.this.removeAllViews();
                HeartBeat.this.addTextView(context);
            }
        });
        ((AnimatedVectorDrawableCompat) drawable).start();
    } else if (drawable instanceof AnimatedVectorDrawable) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            ((AnimatedVectorDrawable) drawable).registerAnimationCallback(new Animatable2.AnimationCallback() {
                @Override
                public void onAnimationEnd(Drawable drawable) {
                    super.onAnimationEnd(drawable);
                    HeartBeat.this.removeAllViews();
                    HeartBeat.this.addTextView(context);
                }
            });
        }
        ((AnimatedVectorDrawable) drawable).start();
    }
}

public void setText(String text) {
    this.mText = text;
}

private void addTextView(Context context) {
    Animation animation = AnimationUtils.loadAnimation(context, R.anim.chat_message);
    animation.reset();
    setAnimation(animation);

    TextView heartBeat = new TextView(context);
    heartBeat.setText(mText);
    heartBeat.setBackgroundResource(R.drawable.bg_chat_message);
    heartBeat.setAnimation(animation);
    HeartBeat.this.addView(heartBeat);
}
}

【问题讨论】:

  • Source code: 请在问题中添加相关代码。我们不应该去任何其他网站查看代码。添加适配器的代码,以及如何向其中添加项目。
  • 请在此处从您的RecyclerView 的适配器添加onBindViewHolder 函数。

标签: android android-recyclerview


【解决方案1】:

我已经检查了您的代码,您需要修改 addItem 类中的 addItem 函数,如下所示。

void addItem(String message) {
    this.messagesList.add(message);
    notifyDataSetChanged();
}

这应该可以回收您的视图。

【讨论】:

  • 理想情况下,您只通知添加了一个项目,而不是整个列表
  • 是的,这是一个改进。谢谢@cricket_007。
  • 我有 notifyDataSetChanged();它没有帮助。这是因为我的特定自定义视图。我可能以一种糟糕的方式过度劳累。
  • 那么你现在可以让它工作吗?还是问题依然存在?
  • 问题依然存在。我稍微更改了自定义视图,现在我使用带有两个视图的 LinearLayout,并且 RecyclerView 保持顺序。不幸的是,当我向 RecycleView 添加超过 7 个项目时,第一个视图(带有动画)停止显示。我也尝试使用 onDraw() 来绘制自定义动画,但是在添加更多元素后,onDraw() 也无法正常工作。我必须放弃我的解决方案。我的目标是创建一个消息列表,类似于以下设计:uplabs.com/posts/medical-bot-interactions
猜你喜欢
  • 2016-11-27
  • 1970-01-01
  • 1970-01-01
  • 2015-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-24
相关资源
最近更新 更多