基于Firebase的习惯追踪应用:连续完成习惯Streak计算实现问询
实现Firebase习惯追踪App的连续完成天数(Streak)计算
核心逻辑概述
由于Firebase仅保存用户勾选过的DailyActivity记录,且列表已按日期降序排列(最新日期在前),我们需要从最新记录开始,逐个验证:
- 当前记录是否为完成状态(
done=true) - 当前记录的日期是否与上一条记录的日期连续(即当前日期是上一条日期的前一天)
一旦遇到未完成记录或日期中断,立即停止计数,统计符合条件的总天数。
步骤1:编写日期工具方法
先实现日期转换和连续日期判断的工具类,简化后续逻辑:
object DateUtils { // 将"yyyy-MM-dd"格式的字符串转为LocalDate fun stringToLocalDate(dateStr: String): LocalDate { return LocalDate.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE) } // 获取指定日期的前一天 fun getPreviousDay(date: LocalDate): LocalDate { return date.minusDays(1) } }
步骤2:在ViewModel中实现Streak计算逻辑
假设ViewModel已持有降序排列的dailyActivities列表,添加计算方法:
class HabitDetailsViewModel : ViewModel() { // 已获取的降序DailyActivity列表 val dailyActivities: LiveData<List<DailyActivity>> = ... // 计算当前连续完成天数 fun calculateCurrentStreak(): Int { val activities = dailyActivities.value ?: return 0 if (activities.isEmpty()) return 0 var streakCount = 0 var lastValidDate: LocalDate? = null for (activity in activities) { // 遇到未完成记录,直接终止计数 if (!activity.done) break val currentDate = DateUtils.stringToLocalDate(activity.date) if (lastValidDate == null) { // 第一条有效记录(最新完成日),计数+1 streakCount++ lastValidDate = currentDate } else { // 验证当前日期是否是上一条有效日期的前一天 val expectedPrevDate = DateUtils.getPreviousDay(lastValidDate) if (currentDate == expectedPrevDate) { streakCount++ lastValidDate = currentDate } else { // 日期中断,终止计数 break } } } return streakCount } }
步骤3:在HabitDetailsActivity中调用并更新UI
观察dailyActivities数据变化,计算并显示连续天数:
class HabitDetailsActivity : AppCompatActivity() { private lateinit var viewModel: HabitDetailsViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_habit_details) viewModel = ViewModelProvider(this)[HabitDetailsViewModel::class.java] viewModel.dailyActivities.observe(this) { val currentStreak = viewModel.calculateCurrentStreak() // 更新UI显示连续天数 streakTextView.text = getString(R.string.current_streak_format, currentStreak) } } }
关键逻辑验证
- 示例场景:仅存在一条
2023-12-28的完成记录,计算结果为1,符合预期。 - 日期中断场景:若记录为
2023-12-28(完成)、2023-12-26(完成),则计数到第一条后,第二条日期不连续,最终streak为1。 - 未完成中断场景:若记录为
2023-12-28(完成)、2023-12-27(未完成),则遍历到第二条时直接终止,streak为1。
内容的提问来源于stack exchange,提问作者Braian Silva
相关产品推荐
相关产品推荐

