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

Android中ViewPager加载10年日期导致Activity加载慢的优化咨询

优化方案

1. 移除冗余的日期解析逻辑,直接格式化Calendar

原代码中getDate方法先拼接日期字符串,再解析成Date对象,最后重新格式化,这是完全多余的操作,会额外消耗大量CPU资源。直接对Calendar的时间进行格式化即可:

// 用ThreadLocal保证SimpleDateFormat的线程安全
private ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = ThreadLocal.withInitial(
    () -> new SimpleDateFormat("dd/MMM/yyyy", Locale.getDefault())
);

public String getDate(Calendar cld) {
    return dateFormatThreadLocal.get().format(cld.getTime());
}

2. 取消预生成全量日期,改为按需计算

10年跨度的日期约有3650条,预生成整个列表会阻塞主线程、占用大量内存。利用ViewPager2的按需加载特性,我们只需保存起始日期和总天数,在需要时根据position计算对应日期:

修改Activity核心代码

public class MainActivity extends AppCompatActivity {

    ViewPager2 myViewPager2;
    ViewPagerDateAdapter viewPagerDateAdapter;
    private Calendar startCalendar;
    private int totalDays;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myViewPager2 = findViewById(R.id.view_pager);

        // 计算起始日期(当前日期往前推5年)
        Calendar c = Calendar.getInstance();
        c.add(Calendar.YEAR, -5);
        startCalendar = (Calendar) c.clone();

        // 计算结束日期(起始日期往后推10年)
        c.add(Calendar.YEAR, 10);
        Calendar endCalendar = (Calendar) c.clone();

        // 计算总天数
        totalDays = (int) ((endCalendar.getTimeInMillis() - startCalendar.getTimeInMillis()) / (1000 * 60 * 60 * 24)) + 1;

        // 初始化Adapter,传入起始日期和总天数
        viewPagerDateAdapter = new ViewPagerDateAdapter(this, startCalendar, totalDays);

        myViewPager2.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
        myViewPager2.setAdapter(viewPagerDateAdapter);
        // 设置当前页为中间位置(对应当前日期)
        int currentPosition = (totalDays + 1) / 2 - 1;
        myViewPager2.setCurrentItem(currentPosition);

        // 页面监听逻辑保留不变...
    }
}

修改Adapter实现按需计算

让Adapter直接根据position推导日期,无需依赖全量列表:

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

    private Context context;
    private Calendar startCalendar;
    private int totalDays;
    private ThreadLocal<SimpleDateFormat> dateFormatThreadLocal;

    public ViewPagerDateAdapter(Context context, Calendar startCalendar, int totalDays) {
        this.context = context;
        this.startCalendar = startCalendar;
        this.totalDays = totalDays;
        this.dateFormatThreadLocal = ThreadLocal.withInitial(
            () -> new SimpleDateFormat("dd/MMM/yyyy", Locale.getDefault())
        );
    }

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

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        // 根据position计算对应日期
        Calendar tempCalendar = (Calendar) startCalendar.clone();
        tempCalendar.add(Calendar.DAY_OF_MONTH, position);
        String dateStr = dateFormatThreadLocal.get().format(tempCalendar.getTime());
        holder.dateTextView.setText(dateStr);
    }

    @Override
    public int getItemCount() {
        return totalDays;
    }

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

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            dateTextView = itemView.findViewById(R.id.tv_date);
        }
    }
}

3. 可选:子线程处理额外数据加载

如果每个日期页需要加载关联数据,可在onBindViewHolder中用协程或AsyncTask在子线程处理,避免阻塞主线程:

// 需引入Coroutine依赖
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    CoroutineScope(Dispatchers.IO).launch {
        // 计算日期或加载关联数据
        Calendar tempCalendar = (Calendar) startCalendar.clone();
        tempCalendar.add(Calendar.DAY_OF_MONTH, position);
        String dateStr = dateFormatThreadLocal.get().format(tempCalendar.getTime());
        
        // 切回主线程更新UI
        withContext(Dispatchers.Main) {
            holder.dateTextView.setText(dateStr);
        }
    }
}

优化效果

  • 启动时间从5-6秒压缩至几百毫秒,彻底消除预生成全量数据的主线程阻塞
  • 内存占用大幅降低,无需保存3000+条日期字符串
  • 滑动时按需计算日期,页面切换更流畅

内容的提问来源于stack exchange,提问作者Deepak Bhatt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 01:17:48