Android端使用Kotlin实现numerator与denominator周自动切换的方法
实现方案
1. 周类型核心计算工具类
优先使用java.time系列API实现逻辑,避免旧Calendar类的周起始日、时区等坑,Android 8.0以下可以通过开启核心库脱糖兼容:
import java.time.DayOfWeek import java.time.LocalDate import java.time.LocalDateTime import java.time.temporal.ChronoUnit import java.time.temporal.TemporalAdjusters enum class WeekType { NUMERATOR, DENOMINATOR } object WeekCalculator { // 替换为你校历中已知为NUMERATOR的任意周一日期作为基准 private val BASE_NUMERATOR_MONDAY: LocalDate = LocalDate.of(2024, 9, 2) fun getCurrentWeekType(): WeekType { val currentMonday = LocalDate.now() .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)) val weeksDiff = ChronoUnit.WEEKS.between(BASE_NUMERATOR_MONDAY, currentMonday) // 偶数间隔为NUMERATOR,奇数为DENOMINATOR,可根据需求调换规则 return if (weeksDiff % 2 == 0L) WeekType.NUMERATOR else WeekType.DENOMINATOR } // 获取下一次切换的日期(本周日0点) fun getNextSwitchTime(): LocalDate = LocalDate.now() .with(TemporalAdjusters.next(DayOfWeek.SUNDAY)) }
如果需要兼容Android 8.0以下版本,在模块级build.gradle中添加脱糖配置即可:
android { defaultConfig { coreLibraryDesugaringEnabled true } } dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' }
2. Fragment实时展示逻辑
在生命周期onResume中触发UI更新,保证用户每次切回页面都能拿到最新的周类型:
class WeekTypeFragment : Fragment() { private var _binding: FragmentWeekTypeBinding? = null private val binding get() = _binding!! private var switchWatcherJob: Job? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentWeekTypeBinding.inflate(inflater, container, false) return binding.root } override fun onResume() { super.onResume() updateWeekTypeDisplay() // 启动周日0点自动切换监听 startAutoSwitchWatcher() } override fun onPause() { super.onPause() // 页面不可见时取消监听,避免资源浪费 switchWatcherJob?.cancel() } private fun updateWeekTypeDisplay() { when(WeekCalculator.getCurrentWeekType()) { WeekType.NUMERATOR -> binding.weekTypeTv.text = "当前为分子周" WeekType.DENOMINATOR -> binding.weekTypeTv.text = "当前为分母周" } } // 前台场景下自动监听切换时间,到点自动刷新UI private fun startAutoSwitchWatcher() { switchWatcherJob?.cancel() switchWatcherJob = viewLifecycleOwner.lifecycleScope.launch { val delayMillis = ChronoUnit.MILLIS.between( LocalDateTime.now(), WeekCalculator.getNextSwitchTime().atStartOfDay() ) delay(delayMillis) updateWeekTypeDisplay() // 重新启动下一轮切换监听 startAutoSwitchWatcher() } } override fun onDestroyView() { super.onDestroyView() _binding = null } }
额外说明
- 如果需要后台场景下也能触发切换通知,可以用
WorkManager设置一次性定时任务,每次切换后重新调度下一次任务即可,功耗远低于常驻服务 - 如果有调休、假期跳过周次的需求,可以在
WeekCalculator中添加排除特定周的逻辑 - 基准周的日期务必根据校历调整,保证周类型计算和学校安排一致
内容的提问来源于stack exchange,提问作者onesector
相关产品推荐
相关产品推荐

