具有项目插入功能的RecyclerView无限滚动

时间:2018-07-06 13:34:29

标签: android android-recyclerview infinite-scroll

我遇到了一个困难的问题,并且在解释它时也遇到了问题,所以请耐心等待

我有无限滚动 RecyclerView(仅从上到下)。

RecyclerView显示电话从第一个到最后一个接收的消息,当到达最后一个消息时,它再次显示第一个消息(仅向下滚动),依此类推。

我通过自动滚动功能实现了该解决方案,该功能始终会增加我的位置,以使其显示平滑滚动到下一个位置。在适配器中,我获得了该项目在列表中的实际位置,并将其绑定到我的视图持有者(即:如果我有2个项目,并且要显示的位置是第5个,则我将获得第一个项目,其逻辑为以这种方式显示项目:1-2-1-2-1)。

我的问题是,一切正常,但是在滚动过程中将新项目添加到数据源并调用NotifyDataSetChangd时,所有内容都会刷新,并且列表会闪烁,从而更改当前显示的项目。

我尝试用一​​个例子来解释这个问题:假设我当前的可见索引是我的无限滚动中的第5个,并且我的来源有2个项目。

正如您在“之前”列中可见的索引5所示,我将看到B项目。

现在,一条消息到达,并通知源,此更改将刷新所有内容。

位置-之前-之后

    0       A        A
    1       B        B
    2       A        C
    3       B        A
    4       A        B
    5       B        C
    6       A        A
    7       B        B
    8       A        C
    9       B        A

现在发生的情况:列表闪烁并显示项目C(后一列的索引5)。

我想要的是:该列表应按现在的顺序显示,并且在实际A-B旋转之后,它会显示新添加的C项目,而不会闪烁和刷新所有内容。

这是适配器(或多或少,它可以完成所有工作,我认为这是唯一重要的代码)

import android.graphics.Typeface;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

import utilitapps.com.ememories.R;
import utilitapps.com.ememories.db_objects.SMSMessage;

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

    private ArrayList<SMSMessage> SMSMessages;
    private int textSize;
    private Typeface custom_font;
    private int lastShownPosition;
    LinkedHashMap<Integer, Integer> offsets;
    Integer lastEntryKey;

    public MessagesAdapter(int textSize, Typeface custom_font, ArrayList<SMSMessage> SMSMessages) {
        this.SMSMessages = SMSMessages;
        this.textSize = textSize;
        this.custom_font = custom_font;
        this.lastShownPosition = 0;
        this.offsets = new LinkedHashMap<>();
        offsets.put(0, -1);
    }

    public void addItem(SMSMessage msg) {
        SMSMessages.add(msg);
        if (SMSMessages.size() > 1) {
            offsets.remove(lastEntryKey);
            offsets.put(lastEntryKey, lastShownPosition);

            //aggiungo poi l'ultima
            lastEntryKey = lastShownPosition + 1;
            offsets.put(lastEntryKey, -1);
        } else {
        }
        notifyDataSetChanged();
    }

    public int getActualItemCount() {
        if (SMSMessages == null) {
            SMSMessages = new ArrayList<>();
        }
        return SMSMessages.size();
    }

    @Override
    public int getItemCount() {
        return Integer.MAX_VALUE;
    }

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


    @Override
    public void onBindViewHolder(@NonNull MessagesAdapter.MessagesViewHolder holder, int position) {
        lastShownPosition = position;
        holder.bind(getSMSMessage(position));
    }

    private SMSMessage getSMSMessage(int position) {
        if (SMSMessages.size() == 0) {
            return null;
        }
        int itemLastIndex = 1;
        for (Map.Entry<Integer, Integer> entry :
                offsets.entrySet()) {
            if (entry.getValue() == -1) {
                return SMSMessages.get(position % SMSMessages.size());
            }
            if (position >= entry.getKey() && position <= entry.getValue()) {
                return SMSMessages.subList(0, itemLastIndex).get(position % SMSMessages.subList(0, itemLastIndex).size());
            }
            itemLastIndex++;
        }
        return null;
    }

    class MessagesViewHolder extends RecyclerView.ViewHolder {

        TextView tvMsgText;

        MessagesViewHolder(View itemView) {
            super(itemView);
            tvMsgText = itemView.findViewById(R.id.tvMsgText);
            tvMsgText.setTextSize(textSize);
            tvMsgText.setTypeface(custom_font);
        }

        void bind(SMSMessage SMSMessage) {
            if (SMSMessage != null && SMSMessage.isValid()) {
                try {
                    tvMsgText.setText(SMSMessage.getMessageText());
                } catch (Exception ignored) {
                    tvMsgText.setText("");
                }
            } else {
                tvMsgText.setText("");
            }
        }
    }
}

如您所见,我尝试实现一个存储索引映射的解决方案,以便我可以用此示例填充列表(遵循以下逻辑:ABAB(添加了项目,但已经加载了A)ABCAB C ...),但不是工作,我不完全理解为什么。

我试图弄清楚,如果不是随意问

感谢帮助

我也对新方法持开放态度,这是我使用过的方法,但可能是错误的,我真的不知道

0 个答案:

没有答案