RecyclerView.Adapter中的大量项目 - 内存问题

时间:2016-04-08 10:22:16

标签: android android-recyclerview

概述:我正在聊天应用程序。直到现在,我正在使用带有Listview的CursorAdapter来加载列表中的聊天项。但是现在,我计划重构代码以使用RecyclerView和RecyclerView.Adapter以及"加载更多"像whatsapp这样的功能。

问题:内存消耗。使用CursorAdapter,不在可查看区域的项目正在收集垃圾,但现在我使用我的CustomModal的ArrayList,一旦你加载列表中的所有项目(通过点击"加载更多&#34 ;按钮)我在内存日志中看到了高内存消耗(No Garbage Collection)。

我现在的猜测是,我正在加载ArrayList中的所有项目并导致问题。是吗?

有没有办法避免问题或优化问题?

修改 : 无法在此处发布完整代码,但这里是我已实施的适配器类型的片段:

public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MyViewHolder> {

    private ArrayList<MyModal> mMyModals;

    public MessageAdapter(ArrayList<MyModal> mMyModals) {
        this.mMyModals = mMyModals;
        //... Some fields initialization here
    }

    public void changeList(ArrayList<MyModal> myModals, boolean isLoadMoreEnabled){
        this.mMyModals = myModals;
        //... Some fields initialization here
        notifyDataSetChanged();
    }

    public void toggleLoadMore(boolean isLoadMoreEnabled){
        if(isLoadMoreEnabled){
            //..Checks if load more is already enabled or not
            //..If not then enables it by adding an item at 0th poition of MyModal list
            //..Then notifyDataSetChanged()
        }else{
            //..Checks if load more is already disabled or not
            //..If not then disables it by removing an item at 0th poition of MyModal list
            //..Then notifyDataSetChanged()
        }
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        MyViewHolder messageViewHolder = null;
        View itemLayoutView = null;

        MyModal.MessageType messageType = MyModal.MessageType.getMessageTypeFromValue(viewType);
        switch (messageType){
            case MESSAGE_TYPE1:
                itemLayoutView = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.layout1, null);
                messageViewHolder = new Type1ViewHolder(itemLayoutView);
                break;
            case MESSAGE_TYPE2:
                itemLayoutView = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.layout2, null);
                messageViewHolder = new Type2ViewHolder(itemLayoutView);
                break;
        }

        return messageViewHolder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        final MyModal myModal = mMyModals.get(position);
        MyModal.MessageType messageType = myModal.getMessageType();
        holder.initialize(myModal);
    }

    @Override
    public int getItemCount() {
        return (mMyModals != null)?mMyModals.size():0;
    }

    @Override
    public int getItemViewType(int position) {
        return mMyModals.get(position).getMessageType().getValue();
    }

    public abstract class MyViewHolder extends RecyclerView.ViewHolder {

        public MyViewHolder(View itemLayoutView) {
            super(itemLayoutView);
        }

        public abstract void initialize(MyModal myModal);
    }

    class Type1ViewHolder extends MyViewHolder {

        //...Variables

        public Type1ViewHolder(View itemLayoutView) {
            super(itemLayoutView);
            //...variables initialization here
        }

        @Override
        public void initialize(MyModal myModal) {
            //...Setting values in view using myModal
        }
    }

    class Type2ViewHolder extends MyViewHolder {

        //...Variables

        public TextViewHolder(View itemLayoutView) {
            super(itemLayoutView);
            //...variables initialization here
        }

        @Override
        public void initialize(MyModal myModal) {
            //...Setting values in view using myModal
        }
    }
}

2 个答案:

答案 0 :(得分:2)

首先:

   public void changeList(ArrayList<MyModal> myModals, boolean isLoadMoreEnabled){
    this.mMyModals = myModals;
    //... Some fields initialization here
    notifyDataSetChanged();
}

在这里,您将创建一个新的arraylist并将其分配给您的mMyModals。这意味着此时有2个arraylists,它们占用的空间量是所需空间的两倍。 GC没有按照你期望的方式工作。由于arraylist在你的活动中初始化,只要arraylist持续存在,它就会持续存在,而最初的arraylist也会如此。

而不是在您的活动中创建新的arraylist并将其传递给changeList。只需清除旧的arraylist并传递它。并且在适配器changeList方法中,您可以执行以下操作

     public void changeList(ArrayList<MyModal> myModals, boolean isLoadMoreEnabled){
    this.mMyModals.clear();
    this.mMyModels.addAll(myModels);
    //... Some fields initialization here
    notifyDataSetChanged();
}

如果我不清楚,请告诉我。如果这不起作用,也会显示您的活动代码。

答案 1 :(得分:1)

请尝试将项目添加到ArrayList,然后调用notifyDataSetChanged,而不是替换整个ArrayList并调用notifyItemRangeInserted(int positionStart, int itemCount),这可能会有效。此外,您无需替换Adapter&#39; ArrayList。您的Activity / Fragment可能具有相同的ArrayList,只需在Activity / Fragment中修改此列表,然后调用notifyItemRangeInserted(int positionStart, int itemCount)即可特技。此外,您还可以尝试仅获取下一个X消息,而不是检索所有消息,因此您不会检索之前已检索过的消息(如果您还没有这样做)。