在 RecyclerView 中,如果频繁刷新 RecyclerView,可能会导致 Native 内存中有大量的 TextView 对象,从而导致内存占用过多的问题。以下是一些可能导致该问题的原因和解决方法:

  1. 使用 ViewHolder

在 RecyclerView 中,使用 ViewHolder 可以避免频繁创建和销毁 View 对象,从而减少内存占用。可以在 RecyclerView.Adapter 中实现 ViewHolder,例如:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.textView.setText("Item " + position);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.text_view);
        }
    }
}
  1. 使用 DiffUtil

在 RecyclerView 中,使用 DiffUtil 可以避免不必要的刷新操作,从而减少内存占用。可以在 RecyclerView.Adapter 中实现 DiffUtil,例如:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private List<String> data = new ArrayList<>();

    public void setData(List<String> newData) {
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MyDiffCallback(data, newData));
        data.clear();
        data.addAll(newData);
        diffResult.dispatchUpdatesTo(this);
    }

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

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.textView.setText(data.get(position));
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.text_view);
        }
    }

    private static class MyDiffCallback extends DiffUtil.Callback {
        private List<String> oldData;
        private List<String> newData;

        public MyDiffCallback(List<String> oldData, List<String> newData) {
            this.oldData = oldData;
            this.newData = newData;
        }

        @Override
        public int getOldListSize() {
            return oldData.size();
        }

        @Override
        public int getNewListSize() {
            return newData.size();
        }

        @Override
        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
            return oldData.get(oldItemPosition).equals(newData.get(newItemPosition));
        }

        @Override
        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
            return oldData.get(oldItemPosition).equals(newData.get(newItemPosition));
        }
    }
}

在更新数据时,可以使用 setData() 方法,并传入新数据,例如:

List<String> newData = new ArrayList<>();
newData.add("Item 1");
newData.add("Item 2");
newData.add("Item 3");
adapter.setData(newData);

这样就可以使用 DiffUtil 来避免不必要的刷新操作,从而减少内存占用。

总之,在使用 RecyclerView 刷新操作时,需要使用 ViewHolder 和 DiffUtil 来优化操作,避免频繁创建和销毁 View 对象,以及避免不必要的刷新操作,从而减少内存占用。


DiffUtil

以下是 RecyclerView 中 DiffUtil 的源码示例,包含 DiffUtil.Callback 和 DiffUtil.DiffResult 两个类的代码:

DiffUtil.Callback:

public abstract static class Callback {
    public abstract int getOldListSize();
    public abstract int getNewListSize();
    public abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition);
    public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition);

    @Nullable
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {
        return null;
    }
}

DiffUtil.DiffResult:

public static class DiffResult {
    private final Callback mCallback;
    private final List<Change> mChanges;
    private final int[] mOldItemStatuses;
    private final int[] mNewItemStatuses;
    private final boolean mDetectMoves;

    DiffResult(Callback callback, List<Change> changes, int[] oldItemStatuses, int[] newItemStatuses, boolean detectMoves) {
        mCallback = callback;
        mChanges = changes;
        mOldItemStatuses = oldItemStatuses;
        mNewItemStatuses = newItemStatuses;
        mDetectMoves = detectMoves;
    }

    public void dispatchUpdatesTo(Adapter adapter) {
        dispatchUpdatesTo(new AdapterListUpdateCallback(adapter));
    }

    public void dispatchUpdatesTo(ListUpdateCallback updateCallback) {
        // ...
    }

    // ...
}

DiffUtil.Callback 是用于比较新旧数据集的回调类,包含以下四个方法:

  1. getOldListSize():获取旧数据集的大小。
  2. getNewListSize():获取新数据集的大小。
  3. areItemsTheSame(int oldItemPosition, int newItemPosition):判断旧数据集中的第 oldItemPosition 项是否与新数据集中的第 newItemPosition 项相同。
  4. areContentsTheSame(int oldItemPosition, int newItemPosition):判断旧数据集中的第 oldItemPosition 项与新数据集中的第 newItemPosition 项的内容是否相同。

DiffUtil.DiffResult 是 DiffUtil 的比较结果类,包含以下方法:

  1. dispatchUpdatesTo(Adapter adapter):将更新结果应用到 RecyclerView.Adapter 中。
  2. dispatchUpdatesTo(ListUpdateCallback updateCallback):将更新结果应用到 ListUpdateCallback 中。
  3. 其他方法用于获取比较结果的详细信息,例如 getOldListSize()、getNewListSize()、getOldPosition(int newPosition)、getNewPosition(int oldPosition) 等。

DiffUtil.DiffResult 中的 dispatchUpdatesTo(Adapter adapter) 方法会调用 AdapterListUpdateCallback 的方法,用于更新 RecyclerView.Adapter,具体实现如下:

private static class AdapterListUpdateCallback implements ListUpdateCallback {
    private final RecyclerView.Adapter mAdapter;

    AdapterListUpdateCallback(RecyclerView.Adapter adapter) {
        mAdapter = adapter;
    }

    @Override
    public void onInserted(int position, int count) {
        mAdapter.notifyItemRangeInserted(position, count);
    }

    @Override
    public void onRemoved(int position, int count) {
        mAdapter.notifyItemRangeRemoved(position, count);
    }

    @Override
    public void onMoved(int fromPosition, int toPosition) {
        mAdapter.notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onChanged(int position, int count, @Nullable Object payload) {
        mAdapter.notifyItemRangeChanged(position, count, payload);
    }
}

在更新 RecyclerView 数据时,可以使用 DiffUtil 的 DiffResult 来避免不必要的刷新操作,从而减少内存占用。

06-13 08:18