代码之家  ›  专栏  ›  技术社区  ›  Pier Giorgio Misley

带项目插入的RecyclerView无限滚动

  •  1
  • Pier Giorgio Misley  · 技术社区  · 7 年前

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

    我有一个 无限滚动 RecyclerView (只从上到下)。

    回收视图 显示手机从第一条到最后一条收到的信息,当到达最后一条时,手机会再次显示第一条(只向下滚动),以此类推。

    我用一个自动滚动功能实现了这个解决方案,它总是增加我的位置,以便平滑地滚动到下一个位置。在适配器中,我获取列表中项目的实际位置,并将其绑定到我的viewholder(即:如果我有两个项目,并且要显示的位置是第五个,我将获取第一个项目,并以这种方式显示项目的逻辑:1-2-1-2-1)。

    我的问题是,一切正常,但当在滚动期间向数据源添加新项时,我调用 NotifyDataSetChangd ,所有内容都会刷新,“我的列表”会闪烁以更改当前显示的项目。

    我试着用一个例子来解释这个问题:假设我当前的可见索引是无限卷轴中的第五个,我的源代码有两项。

    正如你在“之前”一栏中看到的,在可见索引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("");
                }
            }
        }
    }
    

    正如你所看到的,我试图实现一个存储索引映射的解决方案,这样我就可以用这个例子来填充我的列表(遵循以下逻辑:a B a B B(项目已添加,但a已加载)a B C a B C…)但它不起作用,我也不完全理解为什么。

    我尽量说清楚,如果不是随便问的话

    谢谢你的帮助

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

    0 回复  |  直到 7 年前