OpenHarmony 英语学习 App 实战:基于艾宾浩斯曲线的单词复习系统设计

发布时间:2026/7/2 1:59:06

OpenHarmony 英语学习 App 实战:基于艾宾浩斯曲线的单词复习系统设计 OpenHarmony 英语学习 App 实战基于艾宾浩斯曲线的单词复习系统设计摘要背单词最难的不是“第一次记住”而是“过几天还记得”。所以英语学习 App 不能只做词汇列表还需要一套复习调度系统。本文以「英语视界 YingYu」项目为例分享如何在 OpenHarmony/HarmonyOS 应用中实现基于 SM-2 思路的间隔重复复习系统。项目相关文件包括entry/src/main/ets/utils/SpacedRepetition.ts entry/src/main/ets/pages/ReviewCenter.ets entry/src/main/ets/utils/StorageService.ts entry/src/main/ets/model/DataModels.ts本文会从数据模型、算法计算、复习记录、待复习查询、翻转卡片交互几个角度展开。一、为什么要做间隔重复如果用户每天学习 10 个新词30 天就是 300 个。没有复习机制的话用户很快会发现学过的单词不断遗忘学习成就感下降。间隔重复的核心思想是刚学会的单词很快复习熟悉的单词延长复习间隔忘记的单词重新拉回短间隔每次复习结果都会影响下一次复习时间。这比固定“每天复习全部单词”更高效。二、复习记录数据模型项目中使用ReviewRecord描述一个单词的复习状态exportinterfaceReviewRecord {wordId:stringwordType:vocabulary|custom|funEnglish|grammarlearningDate:stringreviewDates:string[]nextReviewDate:stringeaseFactor:numberinterval:numberrepetitions:number}字段说明wordId单词 IDwordType单词来源learningDate首次学习日期reviewDates历史复习日期nextReviewDate下次复习日期easeFactor难度因子interval当前间隔天数repetitions连续记住次数。这几个字段足够支撑一个轻量级复习系统。三、SM-2 参数设计在SpacedRepetition.ts中定义了两个关键参数constMIN_EASE_FACTOR 1.3constINITIAL_EASE_FACTOR 2.5easeFactor可以理解为“这个词对用户来说有多容易”。越容易下一次复习间隔增长越快越难间隔增长越慢。项目还定义了 0-5 的质量等级//0: 完全忘记//1: 错误但看到答案后想起//2: 错误但感觉快想起来了//3: 正确但需要一些努力//4: 正确很快想起//5: 正确非常轻松虽然当前 UI 中使用“认识/不认识”的简化交互但算法层保留质量等级有利于后续扩展更精细的复习反馈。四、计算下一次复习时间核心函数是calculateNextReview()functioncalculateNextReview(record: ReviewRecord, quality: number ): { nextDate: string,interval: number, easeFactor: number, repetitions: number } { let { easeFactor,interval, repetitions } recordeaseFactor easeFactor (0.1- (5- quality) * (0.08 (5- quality) *0.02))if(easeFactor MIN_EASE_FACTOR) { easeFactor MIN_EASE_FACTOR }if(quality 3) { repetitions 0interval1}else{if(repetitions 0) {interval1}elseif(repetitions 1) {interval6}else{interval Math.round(interval* easeFactor) } repetitions }interval Math.min(interval,30) const nextDate newDate() nextDate.setDate(nextDate.getDate() interval)return{ nextDate: nextDate.toISOString().split(T)[0],interval, easeFactor, repetitions } }这段逻辑有几个关键点回答错误重置连续次数间隔回到 1 天第一次记住1 天后复习第二次记住6 天后复习后续记住根据interval * easeFactor拉长间隔最大间隔限制为 30 天避免复习间隔过长。对学生学习 App 来说限制最大间隔很实用因为中小学生词汇量和课程节奏通常需要更频繁的巩固。五、记录一次复习结果当用户完成一次复习时调用recordReview()export function recordReview( wordId:string, wordType: ReviewRecord[wordType], quality:number): ReviewResult { letrecord getReviewRecord(wordId)if(!record) {record createReviewRecord(wordId, wordType) } constresult calculateNextReview(record, quality) const today new Date().toISOString().split(T)[0] const reviewDates [...record.reviewDates, today] const updatedRecord: ReviewRecord { ...record, reviewDates, nextReviewDate:result.nextDate, interval:result.interval, easeFactor:result.easeFactor, repetitions:result.repetitions } updateReviewRecord(wordId, updatedRecord)return{ wordId, quality, newRecord: updatedRecord } }这里遵循了清晰的数据流获取已有复习记录没有记录则创建根据质量等级计算下一次复习写入今天的复习日期更新持久化记录返回更新后的结果。六、创建复习记录复习记录由StorageService.ts创建exportfunctioncreateReviewRecord(wordId:string,wordType: ReviewRecord[wordType]): ReviewRecord { const records getReviewRecords()const today newDate().toISOString().split(T)[0]const nextDate newDate()nextDate.setDate(nextDate.getDate()1) const newRecord: ReviewRecord { wordId, wordType, learningDate: today, reviewDates:[], nextReviewDate: nextDate.toISOString().split(T)[0], easeFactor:2.5, interval:1, repetitions:0} records.push(newRecord) saveReviewRecords(records)return newRecord }首次学习后默认安排第二天复习这符合记忆曲线的基本规律。七、查询今日待复习单词待复习查询逻辑非常直接exportfunctiongetDueReviewWords():ReviewRecord[] {constrecords getReviewRecords()consttoday newDate().toISOString().split(T)[0]returnrecords.filter(rr.nextReviewDate today !r.wordId.startsWith(_mastered_)) }只要nextReviewDate today就说明该单词已经到复习时间。这里还过滤了_mastered_开头的记录便于后续处理“已掌握”或特殊状态。八、今日复习统计首页或复习中心可以通过getTodayReviewStats()展示复习进度exportfunctiongetTodayReviewStats(): {total:number,due:number,reviewed:number,remaining:number} {constrecords getReviewRecords()consttoday newDate().toISOString().split(T)[0]constdue records.filter(rr.nextReviewDate today !r.wordId.startsWith(_mastered_)).lengthconstreviewed records.filter(rr.reviewDates.includes(today)).lengthconsttotal records.lengthconstremaining Math.max(0, due - reviewed)return{ total, due, reviewed, remaining } }再进一步生成提醒文案exportfunctiongetReviewReminderText(): string {conststats getTodayReviewStats()if(stats.due0) {return今日复习已完成}if(stats.remaining0) {return今日复习已完成${stats.reviewed}个}return还有${stats.remaining}个单词等待复习}这种文案可以放在首页、通知、实况窗或每日任务卡片中。九、复习中心翻转卡片交互ReviewCenter.ets中实现了复习页面。页面先加载到期复习单词loadReviewWords() {constdueRecords getDueReviewWords()constallWords getCustomWords()constwordsMap newMapstring,CustomWord()for(leti 0; i allWords.length; i) {constw allWords[i] wordsMap.set(w.id, w) }constitems:ReviewItem[] []for(leti 0; i dueRecords.length; i) {constrecord dueRecords[i]constword wordsMap.get(record.wordId)if(word) { items.push({word: word,record: record }) } }this.reviewItems itemsthis.totalCountthis.reviewItems.length}这里把复习记录和单词详情合并成ReviewItem方便 UI 展示。十、卡片翻转状态复习中心使用isFlipped控制正反面flipCard(){ animateTo({ duration:300, curve: Curve.EaseOut}, () { this.isFlipped !this.isFlipped}) }正面展示英文和音标Text(item.word.word).fontSize(40).fontWeight(FontWeight.Bold)if(item.word.phonetic) {Text(item.word.phonetic).fontSize(20).margin({ top:8}) }反面展示释义和例句Text(item.word.translation).fontSize(28).fontWeight(FontWeight.Bold)if(item.word.example) {Text(item.word.example).fontSize(16).textAlign(TextAlign.Center).margin({ top:20}) }翻转卡片非常适合背单词先回忆再查看答案最后判断是否认识。十一、认识/不认识简化用户反馈当前 UI 中通过两个按钮让用户反馈Button(不认识).onClick(() this.handleReview(false))Button(认识).onClick(() this.handleReview(true))handleReview()根据结果更新间隔if(remembered) {newRepetitionsnewInterval Math.ceil(newInterval*newEaseFactor)newEaseFactor Math.max(1.3,newEaseFactor0.1) }else{newRepetitions0newInterval1newEaseFactor Math.max(1.3,newEaseFactor-0.2) }这是一种更适合低龄用户的交互不要求用户判断 0-5 分只要选择“认识/不认识”。十二、小结本文结合「英语视界 YingYu」项目拆解了一个 OpenHarmony 英语学习 App 的复习系统使用ReviewRecord保存复习状态通过easeFactor、interval、repetitions控制复习节奏使用 SM-2 思路计算下一次复习日期通过getDueReviewWords()查询今日待复习单词使用翻转卡片完成“回忆 - 查看 - 判断”流程通过“认识/不认识”降低操作成本。背单词功能不是词库越大越好真正关键的是让用户在正确的时间复习正确的单词。间隔重复系统就是英语学习 App 的核心发动机之一。

相关新闻