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

Android Fragment切换时Timer已取消但打开新Fragment后仍运行问题

问题根因分析
  • 旧Timer不销毁原因:调用replace + addToBackStack后,旧的timetableFragment并不会被销毁,只是被存入回退栈,所有持有资源(包括Timer)都会继续运行。findFragmentByTag只能匹配当前在容器中活跃的Fragment,回退栈中的Fragment无法被找到,所以你打印的日志一直显示未找到旧Fragment。
  • 取消Timer崩溃原因:Timer实例调用一次cancel()后就进入终止状态,重复调用、或者对未启动/已销毁的Timer调用cancel()都会抛出异常。
修复方案

1. 修复Fragment跳转逻辑

不要全局复用timetableFragment实例,每次点击新建实例,同时统一管理回退栈,避免旧Fragment残留:

holder.itemView.setOnClickListener { v ->
    val activity = v.context as AppCompatActivity
    // 每次点击新建独立实例,不要复用全局trainfragment对象
    val trainfragment = TimetableFragment()
    // 每次新建Bundle,避免参数覆盖
    val bundle = Bundle()
    bundle.putString("ctuid", item.ciftrainid)
    bundle.putString("date", item.rundate)
    trainfragment.arguments = bundle

    val fm = activity.supportFragmentManager
    // 先弹出所有之前的车次详情回退栈,清空残留旧Fragment
    fm.popBackStack("train_stack", FragmentManager.POP_BACK_STACK_INCLUSIVE)

    fm.beginTransaction()
        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
        .replace(R.id.fragmentContainer, trainfragment, "train")
        // 给回退栈设置标记,方便后续批量弹出
        .addToBackStack("train_stack")
        .commit()
}

如果你的业务不需要按返回键回到上一个车次详情,只需要返回列表,可以直接去掉addToBackStack调用,旧Fragment被替换后会直接触发销毁流程。


2. 优化Timer启停逻辑,避免崩溃和内存泄漏

把Timer的生命周期和Fragment可见性绑定,增加状态判断避免重复操作:
首先修改属性声明:

// 改为可空类型,方便手动回收
private var trainScheduleUpdater: Timer? = null
private var isTimerActive = false

在onStart生命周期启动定时器(只有Fragment可见时才运行):

override fun onStart() {
    super.onStart()
    val ctuid = arguments?.getString("ctuid") ?: return
    // 启动前先清理旧的Timer实例
    if (isTimerActive) {
        trainScheduleUpdater?.cancel()
        trainScheduleUpdater?.purge()
    }
    // 新建Timer实例,避免使用已终止的旧实例
    trainScheduleUpdater = Timer()
    trainScheduleUpdater?.scheduleAtFixedRate(
        timerTask {
            activity?.runOnUiThread {
                // 额外校验:Fragment不在前台直接跳过逻辑
                if (!isResumed) return@runOnUiThread
                Log.i("trainTimer", "Timer Has Run for service $ctuid")
                // 你的业务更新逻辑
            }
        },
        0,
        30000 // 按需求设置30秒间隔
    )
    isTimerActive = true
}

在onStop生命周期销毁定时器(Fragment不可见时停止运行):

override fun onStop() {
    super.onStop()
    // 只在定时器运行时执行取消逻辑
    if (isTimerActive) {
        trainScheduleUpdater?.cancel()
        trainScheduleUpdater?.purge()
        trainScheduleUpdater = null
        isTimerActive = false
    }
}

3. 可选优化

Timer是Java旧API,很容易持有Fragment引用导致内存泄漏,建议使用Android Jetpack提供的WorkManager或者Kotlin协程的flow实现定时更新,自带生命周期绑定,不需要手动管理销毁逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 13:54:02