You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含大量长BigInteger的RecyclerView拖动滚动条卡顿崩溃如何解决

卡顿原因分析与优化方案

相关代码

RecyclerAdapter代码

public class CollatzAdapter extends RecyclerView.Adapter<CollatzAdapter.ViewHolder> {

    ArrayList<BigInteger> list = new ArrayList<BigInteger>();
    List<Long> primeList;

    public CollatzAdapter() {
    }

    public CollatzAdapter(ArrayList<BigInteger> list, ArrayList<Long> primeList) {
        this.list = list;
        this.primeList = primeList;
    }
    public CollatzAdapter(ArrayList<BigInteger> list) {
        this.list = list;
    }


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

    @Override
    public void onBindViewHolder(@NonNull CollatzAdapter.ViewHolder holder, int position) {

        holder.mIterationPosition.setText((position + ":"));
        holder.mNumber.setText(list.get(position).toString());

    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {

        public TextView mNumber;
        public TextView mIterationPosition;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            mNumber = itemView.findViewById(R.id.iteration_num);
            mIterationPosition = itemView.findViewById(R.id.iteration_position);
            //mPrime = itemView.findViewById(R.id.iteration_prime);
        }

    }

    public void setList(ArrayList<BigInteger> list) {
        this.list = list;
    }
}

实现逻辑代码

iterationFragment = inflater.inflate(R.layout.fragment_iteration, container, false);
    collatzViewModel = new ViewModelProvider(getActivity()).get(CollatzViewModel.class);

    mRecyclerView = (RecyclerView) iterationFragment.findViewById(R.id.recycler_view);
    mRecyclerView.setHasFixedSize(false);
    mLayoutManager = new LinearLayoutManager(getActivity());

    mAdapter = new CollatzAdapter();
    mRecyclerView.setLayoutManager(mLayoutManager);
    mRecyclerView.setAdapter(mAdapter);

    collatzViewModel.getCollatz().observe(getViewLifecycleOwner(),(list)->{
        mAdapter.setList(list);
        mAdapter.notifyDataSetChanged();
    });

问题现象

当RecyclerView加载包含大量BigInteger的列表时,比如单条BigInteger长度达300字符、总条目数达10万条的场景,拖动滚动条时会出现严重卡顿,甚至会导致应用崩溃。按照RecyclerView的设计逻辑本应仅加载可视区域的少量BigInteger,出现该问题的原因和优化方案如下。


卡顿原因

  • 全量刷新触发冗余重绘:代码中更新数据时使用notifyDataSetChanged(),该方法会强制重绘所有item,完全没有利用RecyclerView的增量更新能力,10万条数据下重绘开销极高。
  • 实时转换字符串阻塞主线程:onBindViewHolder中每次绑定都调用BigInteger.toString(),300位大整数转字符串是重度CPU计算操作,滚动时连续触发会直接阻塞主线程。
  • 布局测量冗余:setHasFixedSize(false)配置会导致每次数据变更时,RecyclerView都要重新测量所有item计算自身大小,10万条数据的测量成本极高。
  • 长文本渲染开销大:300字符的长文本每次绑定都要触发TextView的排版、换行计算,若item布局没有做优化,每个item的渲染成本会进一步升高。
  • 内存抖动和OOM风险:10万条BigInteger本身占用内存较高,滚动时产生的大量临时字符串对象会触发频繁GC,严重时直接导致OOM崩溃。

优化方案

数据层优化

  • 提前缓存字符串结果:ViewModel计算Collatz序列时,直接把所有BigInteger转换成String后再存储,不要在onBindViewHolder中做实时转换,避免滚动时重复计算。
  • 分页加载:不要一次性把10万条数据全部加载进内存,根据滚动位置分批加载,每次仅加载可视区域前后几十条数据即可。

RecyclerView配置优化

  • 修正setHasFixedSize配置:如果RecyclerView的宽高为match_parent或固定值,把setHasFixedSize(false)改成setHasFixedSize(true),避免不必要的全量测量。
  • 替换全量刷新:用DiffUtil做增量更新,仅刷新发生变更的item;首次加载全量数据时,用notifyItemRangeInserted(0, list.size())替代notifyDataSetChanged(),大幅降低更新开销。
  • 增大缓存数量:调用mRecyclerView.setItemViewCacheSize(20),根据单屏显示的item数调整缓存大小,多缓存一倍的item,减少滚动时的创建和绑定次数。

布局与绑定逻辑优化

  • 简化onBindViewHolder逻辑:仅做字符串赋值操作,不要在该方法中做任何计算、格式转换操作。
  • 优化item布局:给显示数字的TextView设置固定宽高,关闭不必要的自动适配、省略号、输入法联想等属性,降低TextView的排版渲染开销。

内容的提问来源于stack exchange,提问作者Erick Sorto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 21:06:03