【鸿蒙心迹】那些凌晨三点的代码,是否也曾点亮过你内心的执着与梦想?
📖 前言
哎呦,各位夜猫子程序员们!提到熬夜写代码,是不是瞬间就想到了那些与咖啡为伴、与bug作战的深夜时光?哈哈哈,别装了,我知道你们都有过那种"就差一点点就能搞定"然后一看时间已经天亮了的经历!
今天想跟大家聊聊我这两年多来为鸿蒙开发熬过的那些夜。说实话,每次回想起那些深夜敲键盘的时光,心情都特别复杂——有疲惫、有焦虑、有挫败,但更多的是那种专注到忘我的纯粹快乐,还有最终完成功能时的巨大成就感。
作为一个资深"熬夜党"(虽然现在已经在努力改正作息,但偶尔还是会为了心爱的项目熬个夜),我想把这些深夜开发的故事分享给大家。那些在黑夜中闪闪发光的代码,那些伴随着鸟鸣声完成的功能,那些让我又爱又恨的bug...它们都是我鸿蒙开发路上最珍贵的回忆。
准备好了吗?让我们一起回到那些充满咖啡因和灵感的深夜时光吧~
☕ 第一个深夜:初入鸿蒙的不眠之夜
还记得我第一次真正意义上为鸿蒙开发熬夜,是在2022年的一个周四晚上。当时我刚开始学习鸿蒙开发,想挑战一下做个稍微复杂一点的项目——一个音乐播放器。
本来想着"就是个播放器嘛,应该很简单吧",结果现实狠狠地打了我脸。光是音频播放的权限申请和生命周期管理就让我头大了!
那天晚上九点开始写代码,想着"最晚十一点就睡觉"。结果一个问题接着一个问题,音频无法播放、进度条不更新、切换歌曲时应用崩溃...每解决一个问题又冒出三个新问题。
深夜一点的时候,我正在跟音频播放的状态管理死磕:
// 那个让我熬夜到天亮的音频播放管理类 - 现在看起来好简单,当时却折腾死我了!
import { media } from '@kit.MediaKit'
import { BusinessError } from '@kit.BasicServicesKit'
@ObservedV2
class AudioPlayerManager {
@Trace isPlaying: boolean = false
@Trace currentTime: number = 0
@Trace duration: number = 0
@Trace currentSong: SongInfo | null = null
@Trace playbackState: string = 'idle' // idle, loading, playing, paused, error
private audioPlayer: media.AVPlayer | null = null
private progressTimer: number = -1
constructor() {
this.initializePlayer()
}
// 初始化播放器 - 这个方法当时让我调试了两个小时!
async initializePlayer() {
try {
console.log('🎵 开始初始化音频播放器...')
this.playbackState = 'loading'
// 创建播放器实例
this.audioPlayer = await media.createAVPlayer()
// 设置状态回调 - 这里的状态管理当时把我绕糊涂了
this.audioPlayer.on('stateChange', (state) => {
console.log(`播放器状态变更: ${state}`)
this.handleStateChange(state)
})
// 播放进度回调
this.audioPlayer.on('timeUpdate', (time) => {
this.currentTime = time
console.log(`播放进度: ${this.formatTime(time)}`)
})
// 播放完成回调
this.audioPlayer.on('endOfStream', () => {
console.log('🎵 歌曲播放完成')
this.onPlaybackComplete()
})
// 错误回调 - 深夜里最不想看到的东西
this.audioPlayer.on('error', (err: BusinessError) => {
console.error(`播放器错误: ${err.code} - ${err.message}`)
this.playbackState = 'error'
this.showErrorMessage(err.message)
})
this.playbackState = 'idle'
console.log('✅ 音频播放器初始化完成!')
} catch (error) {
console.error('💥 播放器初始化失败:', error)
this.playbackState = 'error'
}
}
// 播放歌曲 - 这个方法写了改,改了写,反复折腾
async playSong(song: SongInfo) {
if (!this.audioPlayer) {
console.error('播放器未初始化')
return
}
try {
console.log(`🎵 准备播放: ${song.title} - ${song.artist}`)
this.playbackState = 'loading'
this.currentSong = song
// 设置音频源 - 这里当时各种路径问题
this.audioPlayer.url = song.url
// 准备播放
await this.audioPlayer.prepare()
console.log('✅ 音频准备完成')
// 开始播放
await this.audioPlayer.play()
this.isPlaying = true
this.playbackState = 'playing'
// 启动进度更新定时器
this.startProgressTimer()
console.log(`🎵 正在播放: ${song.title}`)
} catch (error) {
console.error('💥 播放失败:', error)
this.playbackState = 'error'
this.isPlaying = false
}
}
// 暂停/继续播放
async togglePlayback() {
if (!this.audioPlayer || !this.currentSong) return
try {
if (this.isPlaying) {
await this.audioPlayer.pause()
this.isPlaying = false
this.playbackState = 'paused'
this.stopProgressTimer()
console.log('⏸️ 音频已暂停')
} else {
await this.audioPlayer.play()
this.isPlaying = true
this.playbackState = 'playing'
this.startProgressTimer()
console.log('▶️ 音频继续播放')
}
} catch (error) {
console.error('💥 播放控制失败:', error)
}
}
// 处理状态变化 - 当时这个状态机把我搞得头晕眼花
private handleStateChange(state: string) {
console.log(`🔄 播放器状态: ${state}`)
switch (state) {
case 'prepared':
this.duration = this.audioPlayer?.duration || 0
console.log(`歌曲总时长: ${this.formatTime(this.duration)}`)
break
case 'playing':
this.isPlaying = true
this.playbackState = 'playing'
break
case 'paused':
this.isPlaying = false
this.playbackState = 'paused'
break
case 'stopped':
this.isPlaying = false
this.playbackState = 'idle'
this.currentTime = 0
this.stopProgressTimer()
break
}
}
// 进度定时器 - 为了让进度条流畅更新,各种尝试
private startProgressTimer() {
this.stopProgressTimer()
this.progressTimer = setInterval(() => {
if (this.audioPlayer && this.isPlaying) {
// 注意:实际项目中会通过事件回调获取进度,这里简化了
console.log(`📊 更新播放进度: ${this.formatTime(this.currentTime)}`)
}
}, 1000)
}
private stopProgressTimer() {
if (this.progressTimer !== -1) {
clearInterval(this.progressTimer)
this.progressTimer = -1
}
}
// 时间格式化 - 小工具函数
private formatTime(timeMs: number): string {
const seconds = Math.floor(timeMs / 1000)
const minutes = Math.floor(seconds / 60)
const remainingSeconds = seconds % 60
return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`
}
// 播放完成处理
private onPlaybackComplete() {
this.isPlaying = false
this.playbackState = 'idle'
this.currentTime = 0
this.stopProgressTimer()
// 这里可以实现自动播放下一首等逻辑
console.log('🔄 歌曲播放完成,可以播放下一首了')
}
// 错误提示
private showErrorMessage(message: string) {
// 实际项目中会显示Toast或弹窗
console.error(`❌ 播放错误: ${message}`)
}
// 清理资源
async destroy() {
this.stopProgressTimer()
if (this.audioPlayer) {
await this.audioPlayer.release()
this.audioPlayer = null
}
}
}
// 歌曲信息接口
interface SongInfo {
id: string
title: string
artist: string
album: string
url: string
coverUrl?: string
duration?: number
}
就是这个音频播放管理类,让我在深夜里反复调试、修改、测试。每次以为搞定了,运行一下又出新问题。音频不播放、状态错乱、内存泄漏...问题一个接一个。
最要命的是,那时候我对鸿蒙的音频API还不够熟悉,官方文档看起来简单,但实际使用时各种细节问题。我在StackOverflow上搜了一晚上,发现鸿蒙相关的解决方案还不多,只能自己一点点摸索。
凌晨三点的时候,我已经喝了三杯咖啡,眼睛布满血丝,但就是不想放弃。那种"就差一点点就能搞定"的感觉,让我根本停不下来。
终于在凌晨四点半,当我听到测试音频顺利播放,进度条正常更新的那一刻,我差点激动得跳起来!虽然只是一个基础的播放功能,但那种经过长时间努力终于成功的感觉,真的比什么都爽!
那天早上七点,我拖着疲惫的身体去上班,但心里满满的都是成就感。同事们看我黑眼圈这么重,问我是不是熬夜了,我得意地说:"熬夜写代码!音频播放器搞定了!"
现在回想起来,那个晚上的经历让我真正体会到了鸿蒙开发的魅力和挑战。那种在深夜与代码较劲的专注感,那种解决问题后的巨大满足感,深深地吸引着我继续在这条路上走下去。
🐛 第二个深夜:与"幽灵Bug"的生死较量
如果说第一个深夜是因为兴奋和好奇心,那么第二个让我印象深刻的熬夜,就完全是被一个神秘的bug给逼的!那是去年春天的一个周二晚上,我永远忘不了那个让我抓狂到想砸电脑的"幽灵bug"。
当时我正在开发一个鸿蒙的社交应用,功能基本都完成了,准备提交测试版本。结果测试的时候发现一个诡异的问题:应用在使用一段时间后,会突然卡死,然后自动重启。最要命的是,这个问题不是每次都出现,有时候用半小时没事,有时候用五分钟就崩溃。
这种不稳定复现的bug是最让人头疼的!我花了整个白天都没找到问题所在,眼看着deadline就要到了,只能选择熬夜死磕。
晚上九点,我开始了漫长的debug之旅。首先怀疑是内存泄漏,于是一行行检查代码:
// 那个让我熬夜debug的页面管理器 - 问题就藏在这里面!
@ObservedV2
class PageManager {
@Trace pages: Array<PageInfo> = []
@Trace currentPageIndex: number = 0
@Trace isLoading: boolean = false
private pageCache: Map<string, any> = new Map() // 这里有个隐藏的坑!
private navigationStack: Array<string> = []
private eventListeners: Map<string, Function[]> = new Map() // 还有这里!
constructor() {
console.log('📱 PageManager 初始化')
this.initializeEventSystem()
}
// 初始化事件系统
private initializeEventSystem() {
// 监听应用生命周期事件
this.addEventListener('onPageShow', (pageId: string) => {
console.log(`📄 页面显示: ${pageId}`)
this.updatePageStatus(pageId, 'active')
})
this.addEventListener('onPageHide', (pageId: string) => {
console.log(`📄 页面隐藏: ${pageId}`)
this.updatePageStatus(pageId, 'inactive')
})
// 这里是关键!我当时没有正确清理事件监听器
this.addEventListener('onPageDestroy', (pageId: string) => {
console.log(`📄 页面销毁: ${pageId}`)
this.clearPageCache(pageId) // 问题就在这个方法里!
})
}
// 添加事件监听器 - 内存泄漏的源头之一
addEventListener(eventType: string, callback: Function) {
if (!this.eventListeners.has(eventType)) {
this.eventListeners.set(eventType, [])
}
this.eventListeners.get(eventType)?.push(callback)
console.log(`📝 添加事件监听器: ${eventType}, 当前数量: ${this.eventListeners.get(eventType)?.length}`)
// 当时这里缺少了返回清理函数的逻辑!这是内存泄漏的关键问题
// return () => {
// this.removeEventListener(eventType, callback)
// }
}
// 移除事件监听器 - 我当时根本没调用这个方法!
removeEventListener(eventType: string, callback: Function) {
const listeners = this.eventListeners.get(eventType)
if (listeners) {
const index = listeners.indexOf(callback)
if (index > -1) {
listeners.splice(index, 1)
console.log(`🗑️ 移除事件监听器: ${eventType}`)
}
}
}
// 触发事件
private triggerEvent(eventType: string, data?: any) {
const listeners = this.eventListeners.get(eventType)
if (listeners) {
console.log(`🔔 触发事件: ${eventType}, 监听器数量: ${listeners.length}`)
listeners.forEach(callback => {
try {
callback(data)
} catch (error) {
console.error(`❌ 事件回调执行失败: ${eventType}`, error)
}
})
}
}
// 导航到页面
async navigateToPage(pageId: string, params?: any) {
console.log(`🧭 导航到页面: ${pageId}`)
this.isLoading = true
try {
// 检查页面是否已经在缓存中
let pageData = this.pageCache.get(pageId)
if (!pageData) {
// 加载新页面数据
pageData = await this.loadPageData(pageId, params)
this.pageCache.set(pageId, pageData) // 问题:缓存一直增长,从不清理!
console.log(`💾 页面数据已缓存: ${pageId}, 缓存大小: ${this.pageCache.size}`)
}
// 添加到导航栈
this.navigationStack.push(pageId)
// 更新当前页面
const pageIndex = this.pages.findIndex(p => p.id === pageId)
if (pageIndex >= 0) {
this.currentPageIndex = pageIndex
} else {
// 创建新页面
this.pages.push({
id: pageId,
title: pageData.title,
data: pageData,
status: 'loading'
})
this.currentPageIndex = this.pages.length - 1
}
// 触发页面显示事件
this.triggerEvent('onPageShow', pageId)
console.log(`✅ 页面导航完成: ${pageId}`)
} catch (error) {
console.error(`💥 页面导航失败: ${pageId}`, error)
} finally {
this.isLoading = false
}
}
// 加载页面数据 - 模拟异步数据加载
private async loadPageData(pageId: string, params?: any): Promise<any> {
console.log(`📡 加载页面数据: ${pageId}`)
// 模拟网络请求延迟
await new Promise(resolve => setTimeout(resolve, Math.random() * 1000))
// 模拟数据
return {
title: `页面 ${pageId}`,
content: `这是页面 ${pageId} 的内容`,
params: params,
timestamp: Date.now(),
// 这里可能包含大量数据,比如图片、列表等
largeData: new Array(1000).fill(0).map((_, i) => ({
id: i,
value: `数据项 ${i}`
}))
}
}
// 返回上一页
goBack() {
if (this.navigationStack.length > 1) {
// 移除当前页面
const currentPageId = this.navigationStack.pop()
console.log(`🔙 离开页面: ${currentPageId}`)
if (currentPageId) {
this.triggerEvent('onPageHide', currentPageId)
}
// 回到上一页
const previousPageId = this.navigationStack[this.navigationStack.length - 1]
const pageIndex = this.pages.findIndex(p => p.id === previousPageId)
if (pageIndex >= 0) {
this.currentPageIndex = pageIndex
console.log(`📱 返回到页面: ${previousPageId}`)
this.triggerEvent('onPageShow', previousPageId)
}
}
}
// 清理页面缓存 - 这个方法有问题!
private clearPageCache(pageId: string) {
console.log(`🧹 清理页面缓存: ${pageId}`)
// 当时的错误实现 - 只是简单删除,没考虑引用关系
this.pageCache.delete(pageId)
// 但是!事件监听器没有清理,导致内存泄漏
// 而且页面对象可能还被其他地方引用
// 正确的清理应该是这样的(我后来才发现):
// const pageData = this.pageCache.get(pageId)
// if (pageData && pageData.cleanup) {
// pageData.cleanup() // 清理页面内部资源
// }
// this.pageCache.delete(pageId)
//
// // 清理相关事件监听器
// this.eventListeners.forEach((listeners, eventType) => {
// if (listeners.some(l => l.pageId === pageId)) {
// this.eventListeners.set(eventType,
// listeners.filter(l => l.pageId !== pageId))
// }
// })
}
// 更新页面状态
private updatePageStatus(pageId: string, status: string) {
const page = this.pages.find(p => p.id === pageId)
if (page) {
page.status = status
console.log(`🔄 页面状态更新: ${pageId} -> ${status}`)
}
}
// 获取内存使用情况 - 我后来加的debug方法
getMemoryUsage() {
return {
pageCount: this.pages.length,
cacheSize: this.pageCache.size,
navigationStackSize: this.navigationStack.length,
eventListenerCount: Array.from(this.eventListeners.values())
.reduce((total, listeners) => total + listeners.length, 0)
}
}
// 销毁管理器 - 这个方法当时根本没写!
destroy() {
console.log('💥 销毁 PageManager')
// 清理所有缓存
this.pageCache.clear()
// 清理事件监听器
this.eventListeners.clear()
// 清理导航栈
this.navigationStack = []
this.pages = []
}
}
interface PageInfo {
id: string
title: string
data: any
status: string
}
就是这个页面管理器,表面上看起来没什么问题,但实际上有个巨大的内存泄漏陷阱!事件监听器不断累积,页面缓存越来越大,而且从来不清理。随着用户不断操作,内存占用越来越高,最终导致应用崩溃。
但是!当时的我完全没意识到这个问题。我在深夜里反复测试、添加各种日志、怀疑各种可能的原因...从UI渲染问题到网络请求异常,从数据库操作到线程管理,几乎每个模块都检查了一遍。
凌晨两点的时候,我已经喝了四杯咖啡,精神高度紧张但思路越来越乱。那种明明知道有问题但就是找不到的感觉,真的让人抓狂!
突然,在凌晨三点半,我灵光一闪——会不会是内存管理的问题?我赶紧添加了内存使用情况的监控代码:
// 救命的内存监控代码 - 终于让我发现了问题所在!
@Component
struct MemoryMonitor {
@State memoryInfo: string = ''
@State isMonitoring: boolean = false
private monitorTimer: number = -1
startMonitoring() {
this.isMonitoring = true
this.monitorTimer = setInterval(() => {
this.updateMemoryInfo()
}, 5000) // 每5秒检查一次
}
stopMonitoring() {
this.isMonitoring = false
if (this.monitorTimer !== -1) {
clearInterval(this.monitorTimer)
this.monitorTimer = -1
}
}
updateMemoryInfo() {
// 获取页面管理器的内存使用情况
const usage = pageManager.getMemoryUsage()
this.memoryInfo = `
页面数量: ${usage.pageCount}
缓存大小: ${usage.cacheSize}
导航栈: ${usage.navigationStackSize}
事件监听器: ${usage.eventListenerCount}
`
console.log(`📊 内存使用情况: ${this.memoryInfo}`)
// 如果发现异常增长,立即报警!
if (usage.cacheSize > 50 || usage.eventListenerCount > 100) {
console.warn('⚠️ 内存使用异常!可能存在内存泄漏!')
}
}
build() {
Column() {
Text('内存监控')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Text(this.memoryInfo)
.fontSize(12)
.fontFamily('monospace')
.backgroundColor('#F0F0F0')
.padding(10)
.borderRadius(4)
Row() {
Button(this.isMonitoring ? '停止监控' : '开始监控')
.onClick(() => {
if (this.isMonitoring) {
this.stopMonitoring()
} else {
this.startMonitoring()
}
})
Button('手动检查')
.margin({ left: 10 })
.onClick(() => {
this.updateMemoryInfo()
})
}
.margin({ top: 15 })
}
.padding(20)
}
}
当我运行这个内存监控器,开始不断操作应用时,终于发现了问题!缓存大小在疯狂增长,事件监听器数量也在不断累积。每次切换页面,数字都在增加,从来不减少!
天哪!那一刻我简直想给自己一巴掌!这么明显的内存泄漏问题,我竟然折腾了半夜才发现。赶紧修复代码,添加正确的资源清理逻辑...
凌晨四点,当我重新测试应用,看到内存使用量保持稳定,不再异常增长时,那种如释重负的感觉真的无法形容。我瘫坐在椅子上,长长地舒了一口气。
那个晚上的经历让我深刻理解了一个道理:在移动应用开发中,资源管理和内存泄漏防护是多么重要。一个看似无害的设计缺陷,可能会在长时间运行后导致严重问题。
🏃♂️ 第三个深夜:赶项目deadline的疯狂冲刺
说到熬夜开发,怎么能不提那些赶deadline的疯狂时刻呢?去年年底,我参加了一个鸿蒙应用开发大赛,距离提交截止还有48小时,但我的应用还有一大堆功能没完成...
那两天两夜的经历,简直就是一部程序员版的《速度与激情》!我至今还记得那种肾上腺素飙升的刺激感和最后成功提交时的巨大成就感。
当时我做的是一个智能健身助手应用,核心功能是通过鸿蒙设备的传感器实时监测运动数据,提供个性化的健身建议。听起来很酷对吧?但实现起来比想象中复杂太多了!
第一天晚上,我主要在攻克运动数据采集和算法处理:
// 那个让我连续两晚上没睡的运动监测系统 - 现在回想起来都觉得不可思议!
import { sensor } from '@kit.SensorServiceKit'
import { BusinessError } from '@kit.BasicServicesKit'
@ObservedV2
class FitnessTracker {
@Trace isTracking: boolean = false
@Trace currentActivity: ActivityType = 'idle'
@Trace caloriesBurned: number = 0
@Trace stepCount: number = 0
@Trace heartRate: number = 0
@Trace workoutDuration: number = 0 // 秒
// 传感器数据缓存
private accelerometerData: Array<AccelerometerData> = []
private gyroscopeData: Array<GyroscopeData> = []
private heartRateData: Array<number> = []
// 定时器
private trackingTimer: number = -1
private dataProcessTimer: number = -1
private heartRateTimer: number = -1
// AI算法参数 - 这些参数调试了一整夜!
private readonly STEP_THRESHOLD = 1.2 // 加速度阈值
private readonly RUNNING_THRESHOLD = 2.5 // 跑步判断阈值
private readonly CALM_THRESHOLD = 0.5 // 静止判断阈值
constructor() {
console.log('🏃♂️ 健身追踪器初始化')
this.initializeSensors()
}
// 初始化传感器 - 这里各种权限和兼容性问题
async initializeSensors() {
try {
console.log('📱 初始化传感器...')
// 加速度传感器
sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => {
this.processAccelerometerData(data)
}, { interval: 100000000 }) // 10Hz采样
// 陀螺仪传感器
sensor.on(sensor.SensorId.GYROSCOPE, (data: sensor.GyroscopeResponse) => {
this.processGyroscopeData(data)
}, { interval: 100000000 })
// 心率传感器(如果设备支持)
try {
sensor.on(sensor.SensorId.HEART_RATE, (data: sensor.HeartRateResponse) => {
this.processHeartRateData(data)
}, { interval: 1000000000 }) // 1Hz采样
console.log('❤️ 心率传感器已启用')
} catch (error) {
console.warn('⚠️ 心率传感器不可用:', error)
}
console.log('✅ 传感器初始化完成')
} catch (error) {
console.error('💥 传感器初始化失败:', error)
this.handleSensorError(error as BusinessError)
}
}
// 开始运动追踪 - 这个方法写了改,改了写,无数次
async startTracking(activityType: ActivityType = 'walking') {
console.log(`🎯 开始追踪: ${activityType}`)
this.isTracking = true
this.currentActivity = activityType
this.caloriesBurned = 0
this.stepCount = 0
this.workoutDuration = 0
// 清空历史数据
this.accelerometerData = []
this.gyroscopeData = []
this.heartRateData = []
// 启动追踪定时器 - 每秒更新一次
this.trackingTimer = setInterval(() => {
this.workoutDuration++
this.calculateCalories()
console.log(`⏱️ 运动时长: ${this.formatDuration(this.workoutDuration)}`)
}, 1000)
// 启动数据处理定时器 - 每5秒分析一次运动模式
this.dataProcessTimer = setInterval(() => {
this.analyzeMotionPattern()
}, 5000)
console.log('🚀 运动追踪已启动')
}
// 停止追踪
stopTracking() {
console.log('🛑 停止运动追踪')
this.isTracking = false
// 清理定时器
if (this.trackingTimer !== -1) {
clearInterval(this.trackingTimer)
this.trackingTimer = -1
}
if (this.dataProcessTimer !== -1) {
clearInterval(this.dataProcessTimer)
this.dataProcessTimer = -1
}
// 保存运动记录
this.saveWorkoutRecord()
}
// 处理加速度数据 - 步数计算的核心算法
private processAccelerometerData(data: sensor.AccelerometerResponse) {
const magnitude = Math.sqrt(data.x * data.x + data.y * data.y + data.z * data.z)
// 添加到数据缓存
this.accelerometerData.push({
x: data.x,
y: data.y,
z: data.z,
magnitude: magnitude,
timestamp: Date.now()
})
// 保持缓存大小(只保留最近10秒的数据)
if (this.accelerometerData.length > 100) {
this.accelerometerData.shift()
}
// 步数检测算法 - 这个算法调试了一整夜才调对!
this.detectSteps()
// 活动类型推断
this.inferActivityType(magnitude)
}
// 步数检测算法 - 基于加速度峰值检测
private detectSteps() {
if (this.accelerometerData.length < 3) return
const recent = this.accelerometerData.slice(-3)
const [prev, curr, next] = recent
// 检测峰值(当前值大于前后值,且超过阈值)
if (curr.magnitude > prev.magnitude &&
curr.magnitude > next.magnitude &&
curr.magnitude > this.STEP_THRESHOLD) {
// 防止重复计数(相邻峰值间隔至少500ms)
const lastStep = this.accelerometerData
.slice(-10)
.find(d => d.magnitude > this.STEP_THRESHOLD)
if (!lastStep || curr.timestamp - lastStep.timestamp > 500) {
this.stepCount++
console.log(`👣 检测到步数: ${this.stepCount}`)
}
}
}
// 活动类型推断 - 根据运动强度判断运动类型
private inferActivityType(magnitude: number) {
const recentData = this.accelerometerData.slice(-20) // 最近2秒的数据
if (recentData.length < 20) return
const avgMagnitude = recentData.reduce((sum, d) => sum + d.magnitude, 0) / recentData.length
const variance = recentData.reduce((sum, d) => sum + Math.pow(d.magnitude - avgMagnitude, 2), 0) / recentData.length
let newActivity: ActivityType = 'idle'
if (avgMagnitude < this.CALM_THRESHOLD) {
newActivity = 'idle'
} else if (avgMagnitude < this.STEP_THRESHOLD) {
newActivity = 'walking'
} else if (avgMagnitude < this.RUNNING_THRESHOLD) {
newActivity = 'jogging'
} else {
newActivity = 'running'
}
// 只有连续检测到相同活动类型才更新
if (newActivity !== this.currentActivity) {
console.log(`🔄 运动模式变化: ${this.currentActivity} -> ${newActivity}`)
this.currentActivity = newActivity
}
}
// 处理陀螺仪数据 - 用于检测运动方向和姿态
private processGyroscopeData(data: sensor.GyroscopeResponse) {
this.gyroscopeData.push({
x: data.x,
y: data.y,
z: data.z,
timestamp: Date.now()
})
// 保持缓存大小
if (this.gyroscopeData.length > 50) {
this.gyroscopeData.shift()
}
}
// 处理心率数据
private processHeartRateData(data: sensor.HeartRateResponse) {
this.heartRate = data.heartRate
this.heartRateData.push(data.heartRate)
console.log(`❤️ 当前心率: ${this.heartRate} BPM`)
// 保持缓存大小
if (this.heartRateData.length > 60) { // 保留1分钟数据
this.heartRateData.shift()
}
}
// 卡路里计算 - 基于运动类型、体重、心率等因素
private calculateCalories() {
if (!this.isTracking) return
// 基础代谢率(简化计算)
const baseMetabolicRate = 1.2 // 卡/分钟
// 运动强度系数
const activityMultiplier = {
'idle': 1.0,
'walking': 3.0,
'jogging': 6.0,
'running': 10.0
}
// 心率调整系数(如果有心率数据)
let heartRateMultiplier = 1.0
if (this.heartRate > 0) {
// 简化的心率区间计算
if (this.heartRate > 150) {
heartRateMultiplier = 1.5
} else if (this.heartRate > 120) {
heartRateMultiplier = 1.3
} else if (this.heartRate > 100) {
heartRateMultiplier = 1.1
}
}
// 计算当前分钟消耗的卡路里
const caloriesPerMinute = baseMetabolicRate *
activityMultiplier[this.currentActivity] *
heartRateMultiplier
// 累加到总卡路里(每秒调用一次,所以除以60)
this.caloriesBurned += caloriesPerMinute / 60
console.log(`🔥 累计消耗: ${this.caloriesBurned.toFixed(1)} 卡路里`)
}
// 分析运动模式 - 提供个性化建议
private analyzeMotionPattern() {
console.log('🤖 分析运动模式...')
const analysis = {
stepCount: this.stepCount,
currentPace: this.calculatePace(),
avgHeartRate: this.calculateAvgHeartRate(),
caloriesBurned: this.caloriesBurned,
suggestions: this.generateSuggestions()
}
console.log('📊 运动分析结果:', analysis)
// 这里可以触发UI更新,显示实时建议
this.updateUI(analysis)
}
// 计算配速
private calculatePace(): number {
if (this.workoutDuration === 0 || this.stepCount === 0) return 0
// 估算距离(步长约0.7米)
const distance = this.stepCount * 0.7 / 1000 // 公里
const time = this.workoutDuration / 3600 // 小时
return distance / time // 公里/小时
}
// 计算平均心率
private calculateAvgHeartRate(): number {
if (this.heartRateData.length === 0) return 0
return this.heartRateData.reduce((sum, hr) => sum + hr, 0) / this.heartRateData.length
}
// 生成个性化建议
private generateSuggestions(): string[] {
const suggestions: string[] = []
// 基于心率的建议
if (this.heartRate > 0) {
if (this.heartRate > 180) {
suggestions.push('心率过高,建议降低运动强度')
} else if (this.heartRate < 100 && this.currentActivity !== 'idle') {
suggestions.push('可以适当增加运动强度')
}
}
// 基于运动时长的建议
if (this.workoutDuration > 1800) { // 30分钟
suggestions.push('运动时间较长,注意适当休息和补水')
}
// 基于步数的建议
if (this.stepCount > 1000) {
suggestions.push('步数不错!继续保持')
}
return suggestions
}
// 更新UI(实际实现会更新界面显示)
private updateUI(analysis: any) {
// 发送分析结果到UI层
console.log('🖼️ 更新运动界面显示')
}
// 保存运动记录
private saveWorkoutRecord() {
const record = {
date: new Date().toISOString(),
activityType: this.currentActivity,
duration: this.workoutDuration,
stepCount: this.stepCount,
caloriesBurned: this.caloriesBurned,
avgHeartRate: this.calculateAvgHeartRate(),
distance: this.stepCount * 0.7 / 1000 // 估算距离
}
console.log('💾 保存运动记录:', record)
// 实际应用中会保存到数据库或云端
// this.database.saveWorkoutRecord(record)
}
// 格式化时长显示
private formatDuration(seconds: number): string {
const hours = Math.floor(seconds / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
const secs = seconds % 60
if (hours > 0) {
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
} else {
return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}
}
// 错误处理
private handleSensorError(error: BusinessError) {
console.error('❌ 传感器错误:', error.message)
// 实际应用中会显示用户友好的错误提示
}
// 清理资源
destroy() {
console.log('🧹 清理健身追踪器资源')
this.stopTracking()
// 取消传感器监听
try {
sensor.off(sensor.SensorId.ACCELEROMETER)
sensor.off(sensor.SensorId.GYROSCOPE)
sensor.off(sensor.SensorId.HEART_RATE)
} catch (error) {
console.warn('传感器清理失败:', error)
}
}
}
// 数据类型定义
interface AccelerometerData {
x: number
y: number
z: number
magnitude: number
timestamp: number
}
interface GyroscopeData {
x: number
y: number
z: number
timestamp: number
}
type ActivityType = 'idle' | 'walking' | 'jogging' | 'running'
看到这个复杂的健身追踪系统了吗?这就是我在那个疯狂的deadline之夜写出来的!传感器数据采集、步数算法、心率监测、卡路里计算...每一个功能都需要大量的调试和优化。
第一天晚上,我主要在攻克算法问题。步数检测算法特别难调,各种阈值参数需要反复测试。我戴着手机在房间里走来走去,一边走路一边看日志,邻居估计以为我疯了哈哈哈。
凌晨三点的时候,我终于把基本的运动检测功能搞定了。但距离提交还有不到20小时,UI界面还没做,数据存储还没实现,用户体验也需要大幅优化...
第二天(其实已经是凌晨了),我开始疯狂地写UI代码。那种时间紧迫的压力,让我的编程效率达到了前所未有的高度。平时可能需要一天才能写完的界面,我几个小时就搞定了:
// 在极度疲劳状态下写出的UI代码 - 现在看起来都不敢相信是我写的!
@Component
struct FitnessTrackingPage {
@State tracker: FitnessTracker = new FitnessTracker()
@State isTracking: boolean = false
@State selectedActivity: ActivityType = 'walking'
@State showStats: boolean = false
// 实时数据显示
@State displayData: {
steps: number
calories: number
duration: string
heartRate: number
pace: number
} = {
steps: 0,
calories: 0,
duration: '00:00',
heartRate: 0,
pace: 0
}
private updateTimer: number = -1
aboutToAppear() {
console.log('🏃♂️ 健身追踪页面初始化')
this.startDataUpdateTimer()
}
aboutToDisappear() {
if (this.updateTimer !== -1) {
clearInterval(this.updateTimer)
}
this.tracker.destroy()
}
// 开始数据更新定时器
startDataUpdateTimer() {
this.updateTimer = setInterval(() => {
if (this.isTracking) {
this.updateDisplayData()
}
}, 1000)
}
// 更新显示数据
updateDisplayData() {
this.displayData = {
steps: this.tracker.stepCount,
calories: Math.round(this.tracker.caloriesBurned),
duration: this.formatDuration(this.tracker.workoutDuration),
heartRate: this.tracker.heartRate,
pace: this.calculatePace()
}
}
// 开始/停止追踪
toggleTracking() {
if (this.isTracking) {
this.tracker.stopTracking()
this.isTracking = false
console.log('🛑 停止健身追踪')
} else {
this.tracker.startTracking(this.selectedActivity)
this.isTracking = true
console.log(`🚀 开始${this.selectedActivity}追踪`)
}
}
// 计算配速
calculatePace(): number {
// 简化的配速计算
return this.tracker.stepCount > 0 ?
(this.tracker.workoutDuration / 60) / (this.tracker.stepCount * 0.7 / 1000) : 0
}
// 格式化时长
formatDuration(seconds: number): string {
const mins = Math.floor(seconds / 60)
const secs = seconds % 60
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}
build() {
Column() {
// 顶部状态栏
this.buildStatusBar()
// 主要数据显示区域
this.buildMainDataDisplay()
// 控制按钮区域
this.buildControlButtons()
// 统计图表区域(如果显示)
if (this.showStats) {
this.buildStatsChart()
}
}
.width('100%')
.height('100%')
.backgroundColor('#F5F7FA')
.padding({ top: 20 })
}
// 构建状态栏
@Builder buildStatusBar() {
Row() {
Text('🏃♂️ 智能健身助手')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
Blank()
Text(this.isTracking ? '●运动中' : '○待机')
.fontSize(14)
.fontColor(this.isTracking ? Color.Red : Color.Grey)
.animation({ duration: 1000 })
}
.width('100%')
.padding({ horizontal: 20, vertical: 10 })
.backgroundColor(Color.White)
.borderRadius(12)
.margin({ horizontal: 16, bottom: 20 })
}
// 构建主数据显示区域
@Builder buildMainDataDisplay() {
Column() {
// 运动类型选择
if (!this.isTracking) {
this.buildActivitySelector()
}
// 核心数据展示
Grid() {
GridItem() {
this.buildDataCard('👣', '步数', this.displayData.steps.toString(), 'steps')
}
GridItem() {
this.buildDataCard('🔥', '卡路里', this.displayData.calories.toString(), 'kcal')
}
GridItem() {
this.buildDataCard('⏱️', '时长', this.displayData.duration, 'min')
}
GridItem() {
this.buildDataCard('❤️', '心率', this.displayData.heartRate.toString(), 'bpm')
}
}
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr')
.rowsGap(12)
.columnsGap(12)
.height(200)
.margin({ bottom: 20 })
}
.width('100%')
.padding({ horizontal: 16 })
}
// 构建运动类型选择器
@Builder buildActivitySelector() {
Column() {
Text('选择运动类型')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.margin({ bottom: 12 })
Row() {
['walking', 'jogging', 'running'].forEach((activity: ActivityType, index) => {
Button(this.getActivityName(activity))
.fontSize(14)
.backgroundColor(this.selectedActivity === activity ? '#007AFF' : '#E5E5E5')
.fontColor(this.selectedActivity === activity ? Color.White : '#333333')
.borderRadius(20)
.padding({ horizontal: 16, vertical: 8 })
.margin({ right: index < 2 ? 12 : 0 })
.onClick(() => {
this.selectedActivity = activity
console.log(`选择运动类型: ${activity}`)
})
})
}
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(12)
.margin({ horizontal: 16, bottom: 20 })
}
// 构建数据卡片
@Builder buildDataCard(icon: string, label: string, value: string, unit: string) {
Column() {
Text(icon)
.fontSize(24)
.margin({ bottom: 8 })
Text(value)
.fontSize(32)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
.margin({ bottom: 4 })
Text(`${label} (${unit})`)
.fontSize(12)
.fontColor('#666666')
}
.width('100%')
.height('100%')
.backgroundColor(Color.White)
.borderRadius(12)
.padding(12)
.justifyContent(FlexAlign.Center)
// 添加一些动画效果
.scale({ x: this.isTracking ? 1.02 : 1.0, y: this.isTracking ? 1.02 : 1.0 })
.animation({ duration: 300, curve: Curve.EaseInOut })
}
// 构建控制按钮区域
@Builder buildControlButtons() {
Column() {
// 主控制按钮
Button(this.isTracking ? '🛑 停止运动' : '🚀 开始运动')
.width('80%')
.height(50)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.backgroundColor(this.isTracking ? '#FF3B30' : '#34C759')
.fontColor(Color.White)
.borderRadius(25)
.onClick(() => {
this.toggleTracking()
})
.margin({ bottom: 16 })
// 辅助功能按钮
Row() {
Button('📊 统计')
.fontSize(14)
.backgroundColor('#007AFF')
.fontColor(Color.White)
.borderRadius(20)
.padding({ horizontal: 20, vertical: 10 })
.onClick(() => {
this.showStats = !this.showStats
console.log('切换统计显示')
})
Button('📋 历史')
.fontSize(14)
.backgroundColor('#007AFF')
.fontColor(Color.White)
.borderRadius(20)
.padding({ horizontal: 20, vertical: 10 })
.margin({ left: 12 })
.onClick(() => {
console.log('显示历史记录')
})
Button('⚙️ 设置')
.fontSize(14)
.backgroundColor('#007AFF')
.fontColor(Color.White)
.borderRadius(20)
.padding({ horizontal: 20, vertical: 10 })
.margin({ left: 12 })
.onClick(() => {
console.log('打开设置')
})
}
}
.width('100%')
.padding({ horizontal: 16 })
}
// 构建统计图表区域
@Builder buildStatsChart() {
Column() {
Text('📈 运动统计')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 12 })
// 简化的图表显示(实际项目中会用专业图表库)
Row() {
Text('步数趋势: 📈')
Text('心率变化: 💓')
Text('卡路里: 🔥')
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
Text('详细图表功能开发中...')
.fontSize(14)
.fontColor('#666666')
.margin({ top: 20 })
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(12)
.margin({ horizontal: 16, top: 20 })
}
// 获取运动类型显示名称
getActivityName(activity: ActivityType): string {
const names = {
'walking': '🚶♂️ 走路',
'jogging': '🏃♂️ 慢跑',
'running': '🏃♂️ 跑步',
'idle': '😴 休息'
}
return names[activity] || activity
}
}
这套UI代码是我在极度疲劳的状态下,靠着咖啡和意志力硬撑着写出来的。现在回看代码,发现很多地方写得其实挺粗糙,但在当时的时间压力下,能跑起来就已经是奇迹了!
第二天凌晨五点,距离提交截止还有3小时,我终于把所有核心功能都实现了。但这时候又发现了一个严重问题——应用在某些设备上会崩溃!
天哪!那一刻我真的快崩溃了。熬了两个晚上,眼看就要完成,结果又出现这种问题。我赶紧加了大量的异常处理和兼容性代码,一边修bug一边测试...
最后半小时,我连续提交了三个版本,每次都发现新问题然后紧急修复。当我在截止前5分钟成功提交最终版本时,整个人都虚脱了。
那种48小时不合眼,靠着咖啡和肾上腺素支撑,最终成功完成项目的体验,真的让我终生难忘。虽然过程很痛苦,但那种挑战自己极限、在压力下迸发出超强能力的感觉,也是一种独特的成就感。
更让我惊喜的是,这个应用后来在比赛中获得了三等奖!评委们特别认可了运动算法的创新性和用户体验的流畅性。那种努力得到回报的感觉,让之前所有的熬夜都变得值得了。
🌅 第四个深夜:为了完美而执着的那一夜
有时候熬夜,不是因为deadline的压力,而是因为内心对完美的执着追求。那种"这个功能还能更好一点"的想法,会让你不知不觉就熬到天亮。
去年夏天的一个晚上,我正在优化一个鸿蒙应用的动画效果。本来这个动画已经足够流畅了,用户体验也不错,但我总觉得还能做得更好。于是开始了一场与自己较劲的深夜之旅...
那天晚上,我想实现一个特别炫酷的页面切换动画。不是普通的左右滑动,而是类似翻书效果的3D动画,每个页面都有深度感和真实的物理反馈。
// 为了追求完美而熬夜写的3D翻页动画 - 现在看起来都觉得当时好疯狂!
@ObservedV2
class PageFlipAnimation {
@Trace currentPage: number = 0
@Trace totalPages: number = 5
@Trace isAnimating: boolean = false
@Trace flipProgress: number = 0 // 0-1之间,表示翻页进度
@Trace flipDirection: 'left' | 'right' = 'right'
// 动画参数 - 这些参数我调了整整一夜!
private readonly FLIP_DURATION = 800 // 动画持续时间(ms)
private readonly FLIP_RESISTANCE = 0.3 // 翻页阻力系数
private readonly SPRING_DAMPING = 0.8 // 弹簧阻尼
private readonly PERSPECTIVE_DISTANCE = 1000 // 3D透视距离
// 动画控制
private animationId: number = -1
private startTime: number = 0
private startProgress: number = 0
private targetProgress: number = 0
// 手势识别
private panStartX: number = 0
private panStartProgress: number = 0
private panVelocity: number = 0
constructor() {
console.log('📖 3D翻页动画系统初始化')
}
// 开始翻页动画 - 这个方法写了无数遍,每次都想着能不能更完美
flipToPage(targetPage: number, duration: number = this.FLIP_DURATION) {
if (this.isAnimating || targetPage === this.currentPage) return
console.log(`📖 开始翻页: ${this.currentPage} -> ${targetPage}`)
this.isAnimating = true
this.flipDirection = targetPage > this.currentPage ? 'right' : 'left'
// 设置动画参数
this.startTime = Date.now()
this.startProgress = this.flipProgress
this.targetProgress = this.flipDirection === 'right' ? 1 : 0
// 启动动画循环
this.startAnimationLoop(duration)
}
// 动画循环 - 60FPS的丝滑动画
private startAnimationLoop(duration: number) {
this.stopAnimationLoop()
const animate = () => {
const now = Date.now()
const elapsed = now - this.startTime
const progress = Math.min(elapsed / duration, 1)
// 使用缓动函数让动画更自然 - 这个缓动函数调了好久!
const easedProgress = this.easeOutCubic(progress)
// 更新翻页进度
this.flipProgress = this.lerp(this.startProgress, this.targetProgress, easedProgress)
console.log(`📖 翻页进度: ${(this.flipProgress * 100).toFixed(1)}%`)
if (progress < 1) {
// 动画未完成,继续下一帧
this.animationId = requestAnimationFrame(animate)
} else {
// 动画完成
this.onAnimationComplete()
}
}
this.animationId = requestAnimationFrame(animate)
}
// 停止动画循环
private stopAnimationLoop() {
if (this.animationId !== -1) {
cancelAnimationFrame(this.animationId)
this.animationId = -1
}
}
// 动画完成处理
private onAnimationComplete() {
console.log('📖 翻页动画完成')
// 更新当前页面
if (this.flipDirection === 'right' && this.flipProgress >= 0.5) {
this.currentPage = Math.min(this.currentPage + 1, this.totalPages - 1)
} else if (this.flipDirection === 'left' && this.flipProgress <= 0.5) {
this.currentPage = Math.max(this.currentPage - 1, 0)
}
// 重置动画状态
this.isAnimating = false
this.flipProgress = 0
console.log(`📖 当前页面: ${this.currentPage}`)
}
// 处理手势开始
onPanStart(x: number) {
console.log(`👆 开始手势: x=${x}`)
this.stopAnimationLoop()
this.panStartX = x
this.panStartProgress = this.flipProgress
this.panVelocity = 0
}
// 处理手势移动 - 这里的物理计算让我头大了好久
onPanUpdate(x: number, screenWidth: number) {
const deltaX = x - this.panStartX
const progress = Math.abs(deltaX) / screenWidth
// 添加阻力效果 - 越接近边界阻力越大
const resistance = this.calculateResistance(progress)
const adjustedProgress = progress * resistance
// 判断翻页方向
if (deltaX > 0 && this.currentPage > 0) {
// 向右滑,翻到上一页
this.flipDirection = 'left'
this.flipProgress = Math.min(adjustedProgress, 1)
} else if (deltaX < 0 && this.currentPage < this.totalPages - 1) {
// 向左滑,翻到下一页
this.flipDirection = 'right'
this.flipProgress = Math.min(adjustedProgress, 1)
}
// 计算手势速度(用于后续的惯性动画)
this.panVelocity = deltaX / 16 // 假设16ms一帧
console.log(`👆 手势更新: progress=${this.flipProgress.toFixed(2)}, velocity=${this.panVelocity.toFixed(2)}`)
}
// 处理手势结束 - 决定翻页还是回弹
onPanEnd(screenWidth: number) {
console.log(`👆 手势结束: progress=${this.flipProgress.toFixed(2)}, velocity=${this.panVelocity}`)
// 根据翻页进度和手势速度决定最终状态
const shouldFlip = this.shouldCompletePage(this.flipProgress, this.panVelocity)
if (shouldFlip) {
// 完成翻页
const remainingDistance = 1 - this.flipProgress
const duration = remainingDistance * this.FLIP_DURATION
this.flipToPage(
this.flipDirection === 'right' ? this.currentPage + 1 : this.currentPage - 1,
Math.max(duration, 200) // 最少200ms
)
} else {
// 回弹到原位置
this.springBack()
}
}
// 计算阻力系数 - 让手势感觉更真实
private calculateResistance(progress: number): number {
// 使用指数衰减函数模拟阻力
return Math.exp(-progress * this.FLIP_RESISTANCE)
}
// 判断是否应该完成翻页
private shouldCompletePage(progress: number, velocity: number): boolean {
// 如果进度超过50%,或者速度足够大,就完成翻页
return progress > 0.5 || Math.abs(velocity) > 5
}
// 回弹动画
private springBack() {
console.log('📖 执行回弹动画')
this.isAnimating = true
this.startTime = Date.now()
this.startProgress = this.flipProgress
this.targetProgress = 0
// 使用弹簧动画
this.startSpringAnimation()
}
// 弹簧动画 - 物理模拟让动画更真实
private startSpringAnimation() {
let velocity = this.panVelocity * 0.1 // 缩放速度
let displacement = this.startProgress
const animate = () => {
// 简化的弹簧物理模型
const springForce = -displacement * 0.8 // 弹性力
const dampingForce = -velocity * this.SPRING_DAMPING // 阻尼力
const totalForce = springForce + dampingForce
// 更新速度和位移
velocity += totalForce * 0.016 // 假设16ms一帧
displacement += velocity * 0.016
this.flipProgress = Math.max(0, displacement)
// 检查是否停止(位移和速度都很小)
if (Math.abs(displacement) < 0.001 && Math.abs(velocity) < 0.01) {
this.flipProgress = 0
this.isAnimating = false
console.log('📖 回弹动画完成')
} else {
this.animationId = requestAnimationFrame(animate)
}
}
this.animationId = requestAnimationFrame(animate)
}
// 缓动函数 - 让动画看起来更自然
private easeOutCubic(t: number): number {
return 1 - Math.pow(1 - t, 3)
}
// 线性插值
private lerp(start: number, end: number, t: number): number {
return start + (end - start) * t
}
// 获取当前页面的3D变换参数 - 这里的数学计算把我折磨死了!
getCurrentPageTransform(): PageTransform {
const rotationY = this.flipProgress * 180 // 0-180度
const translateZ = Math.sin(this.flipProgress * Math.PI) * 100 // 弯曲效果
const opacity = Math.cos(this.flipProgress * Math.PI * 0.5)
return {
rotateY: this.flipDirection === 'right' ? -rotationY : rotationY,
translateZ: translateZ,
opacity: opacity,
scale: 1 - this.flipProgress * 0.1 // 轻微缩放
}
}
// 获取下一页的3D变换参数
getNextPageTransform(): PageTransform {
const rotationY = (1 - this.flipProgress) * 180
const translateZ = Math.sin((1 - this.flipProgress) * Math.PI) * 100
const opacity = Math.cos((1 - this.flipProgress) * Math.PI * 0.5)
return {
rotateY: this.flipDirection === 'right' ? 180 - rotationY : -(180 - rotationY),
translateZ: translateZ,
opacity: opacity,
scale: 0.9 + this.flipProgress * 0.1
}
}
// 清理资源
destroy() {
console.log('📖 清理3D翻页动画资源')
this.stopAnimationLoop()
}
}
// 变换参数接口
interface PageTransform {
rotateY: number
translateZ: number
opacity: number
scale: number
}
// 实际使用的组件
@Component
struct FlipBookPage {
@State animator: PageFlipAnimation = new PageFlipAnimation()
@State pageContents: string[] = ['页面1', '页面2', '页面3', '页面4', '页面5']
build() {
Stack() {
// 当前页面
this.buildPage(
this.pageContents[this.animator.currentPage],
this.animator.getCurrentPageTransform(),
'#4A90E2'
)
// 下一页(如果正在翻页)
if (this.animator.isAnimating) {
const nextPageIndex = this.animator.flipDirection === 'right' ?
this.animator.currentPage + 1 : this.animator.currentPage - 1
if (nextPageIndex >= 0 && nextPageIndex < this.pageContents.length) {
this.buildPage(
this.pageContents[nextPageIndex],
this.animator.getNextPageTransform(),
'#E74C3C'
)
}
}
}
.width('100%')
.height('100%')
.backgroundColor('#2C3E50')
.gesture(
PanGesture({ fingers: 1, direction: PanDirection.Horizontal })
.onActionStart((event) => {
this.animator.onPanStart(event.fingerList[0].localX)
})
.onActionUpdate((event) => {
this.animator.onPanUpdate(event.fingerList[0].localX, 360) // 假设屏幕宽度360
})
.onActionEnd((event) => {
this.animator.onPanEnd(360)
})
)
}
@Builder buildPage(content: string, transform: PageTransform, color: string) {
Column() {
Text(content)
.fontSize(32)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
Text(`第 ${this.animator.currentPage + 1} 页`)
.fontSize(16)
.fontColor('#CCCCCC')
.margin({ top: 20 })
}
.width('80%')
.height('60%')
.backgroundColor(color)
.borderRadius(12)
.justifyContent(FlexAlign.Center)
.rotate({
y: 1,
angle: transform.rotateY,
centerX: '50%',
centerY: '50%'
})
.translate({
z: transform.translateZ
})
.opacity(transform.opacity)
.scale({
x: transform.scale,
y: transform.scale
})
.animation({
duration: 16, // 60FPS
curve: Curve.Linear
})
}
}
看到这个复杂的3D翻页动画系统了吗?这就是我为了追求完美效果而熬夜写出来的!每一个参数、每一个缓动函数、每一个物理模拟,我都反复调试、优化,想要达到最真实、最流畅的效果。
那个晚上,我一遍遍地测试动画效果,调整各种参数。阻力系数调小了会感觉太轻飘,调大了又会感觉拖沓。弹簧阻尼系数不对,回弹动画就不自然。3D变换的角度计算错了,翻页效果就会很奇怪...
凌晨三点的时候,我终于调出了一个比较满意的效果。但当我准备休息时,突然想到:"会不会还能加个阴影效果?让页面看起来更有立体感?"
于是又开始了新一轮的折腾...添加动态阴影、调整光照效果、优化渲染性能...不知不觉又是两个小时过去了。
当天空开始泛白,我看着屏幕上那个近乎完美的翻页动画时,虽然疲惫不堪,但心里满满的都是成就感。那种为了追求极致而忘记时间的专注状态,就是程序员独有的浪漫吧。
后来这个3D翻页动画被很多朋友夸赞,有人甚至问我是不是用了什么高级的动画库。当我告诉他们这是我从零开始,一行行代码手写出来的时候,他们都惊呆了。
这就是深夜开发的魅力——在安静的夜晚,没有干扰,只有你和代码。那种纯粹的创造快乐,让你忘记疲劳,忘记时间,只想把心中的想法完美地实现出来。
🎨 第五个深夜:灵感突发的创作之夜
最后要聊的这个熬夜经历,是最特别的一次。那不是因为bug,不是因为deadline,也不是因为追求完美,而是因为突然迸发的灵感!
那是今年春天的一个周六晚上,我正在刷社交媒体放松,突然看到一个朋友发了个状态:"哎,总是记不住朋友们的生日,每次都是看到朋友圈才想起来,好尴尬..."
这个抱怨触发了我的灵感——为什么不做一个智能的生日提醒应用呢?但不是普通的提醒,而是能够根据关系亲密度、个人习惯、甚至当前心情来智能安排提醒和祝福方式的应用!
一想到这个点子,我就兴奋得睡不着觉。立马打开电脑开始构思架构,那种创作的冲动让我根本停不下来:
// 灵感迸发的智能生日助手 - 那个让我一夜不眠的创意项目!
@ObservedV2
class SmartBirthdayAssistant {
@Trace upcomingBirthdays: Array<BirthdayEvent> = []
@Trace todayBirthdays: Array<BirthdayEvent> = []
@Trace relationshipAnalysis: Map<string, RelationshipData> = new Map()
@Trace reminderSettings: ReminderSettings = new ReminderSettings()
// AI助手核心 - 这个想法让我整夜兴奋!
private personalityAnalyzer: PersonalityAnalyzer = new PersonalityAnalyzer()
private greetingGenerator: GreetingGenerator = new GreetingGenerator()
private optimalTimingCalculator: OptimalTimingCalculator = new OptimalTimingCalculator()
constructor() {
console.log('🎂 智能生日助手启动!')
this.initializeAI()
this.loadBirthdayData()
this.startIntelligentMonitoring()
}
// 初始化AI系统 - 让应用真正"智能"
async initializeAI() {
console.log('🧠 初始化AI分析系统...')
try {
// 分析用户的社交模式
await this.personalityAnalyzer.analyzeSocialPattern()
// 学习用户的祝福习惯
await this.greetingGenerator.learnUserStyle()
// 计算最佳提醒时机
await this.optimalTimingCalculator.analyzeUserBehavior()
console.log('🎯 AI系统初始化完成!')
} catch (error) {
console.error('❌ AI初始化失败:', error)
}
}
// 添加朋友生日 - 不只是添加,还要智能分析关系
async addFriendBirthday(friendInfo: FriendInfo) {
console.log(`👥 添加朋友生日: ${friendInfo.name}`)
// 创建生日事件
const birthdayEvent: BirthdayEvent = {
id: this.generateId(),
friendId: friendInfo.id,
name: friendInfo.name,
birthday: friendInfo.birthday,
avatar: friendInfo.avatar,
relationshipLevel: await this.analyzeRelationship(friendInfo),
lastGreeting: null,
greetingHistory: [],
preferences: {
favoriteColors: friendInfo.favoriteColors || [],
hobbies: friendInfo.hobbies || [],
personalityTags: friendInfo.personalityTags || []
}
}
// 智能分析关系亲密度
const relationshipData = await this.personalityAnalyzer.analyzeRelationship(friendInfo)
this.relationshipAnalysis.set(friendInfo.id, relationshipData)
// 计算最佳提醒策略
const reminderStrategy = await this.optimalTimingCalculator.calculateStrategy(birthdayEvent, relationshipData)
birthdayEvent.reminderStrategy = reminderStrategy
// 保存数据
this.saveBirthdayEvent(birthdayEvent)
// 更新提醒列表
this.updateUpcomingBirthdays()
console.log(`✅ 朋友生日已添加,关系等级: ${relationshipData.level}`)
}
// 智能生成个性化祝福 - 这是整个应用的核心亮点!
async generatePersonalizedGreeting(friendId: string): Promise<PersonalizedGreeting> {
console.log(`🎨 为朋友 ${friendId} 生成个性化祝福`)
const birthdayEvent = this.findBirthdayEvent(friendId)
const relationshipData = this.relationshipAnalysis.get(friendId)
if (!birthdayEvent || !relationshipData) {
throw new Error('朋友信息不完整')
}
// 基于AI分析生成祝福内容
const greetingContent = await this.greetingGenerator.generateGreeting({
friendName: birthdayEvent.name,
relationshipLevel: relationshipData.level,
personalityTags: birthdayEvent.preferences.personalityTags,
hobbies: birthdayEvent.preferences.hobbies,
recentInteractions: relationshipData.recentInteractions,
greetingHistory: birthdayEvent.greetingHistory
})
// 选择最佳的祝福媒体形式
const mediaType = this.selectOptimalMediaType(relationshipData)
// 计算最佳发送时间
const optimalTime = await this.optimalTimingCalculator.calculateOptimalTime(friendId)
const personalizedGreeting: PersonalizedGreeting = {
content: greetingContent,
mediaType: mediaType,
optimalSendTime: optimalTime,
confidence: greetingContent.confidence,
alternatives: greetingContent.alternatives
}
console.log(`🎯 个性化祝福生成完成,置信度: ${personalizedGreeting.confidence}%`)
return personalizedGreeting
}
// 选择最佳祝福媒体类型
private selectOptimalMediaType(relationshipData: RelationshipData): MediaType {
// 基于关系亲密度和个人偏好选择
if (relationshipData.level >= 8) {
// 非常亲密的朋友 - 语音或视频祝福
return relationshipData.preferredContactMethod === 'call' ? 'voice_message' : 'video_message'
} else if (relationshipData.level >= 5) {
// 比较亲密 - 个性化图片或长文字
return relationshipData.visualPreference ? 'custom_image' : 'long_text'
} else {
// 普通朋友 - 简短文字或表情包
return relationshipData.humorLevel > 6 ? 'meme' : 'short_text'
}
}
// 智能提醒系统 - 根据用户习惯和朋友重要性安排提醒
startIntelligentMonitoring() {
console.log('🔔 启动智能提醒监控')
// 每小时检查一次提醒任务
setInterval(() => {
this.checkReminders()
}, 60 * 60 * 1000)
// 每天凌晨更新生日列表
setInterval(() => {
this.updateDailyBirthdays()
}, 24 * 60 * 60 * 1000)
}
// 检查并执行提醒
private async checkReminders() {
const now = new Date()
console.log(`⏰ 检查提醒任务: ${now.toLocaleTimeString()}`)
for (const birthday of this.upcomingBirthdays) {
if (!birthday.reminderStrategy) continue
for (const reminder of birthday.reminderStrategy.reminders) {
if (this.shouldTriggerReminder(reminder, now)) {
await this.triggerSmartReminder(birthday, reminder)
}
}
}
}
// 触发智能提醒
private async triggerSmartReminder(birthday: BirthdayEvent, reminder: ReminderConfig) {
console.log(`🎯 触发智能提醒: ${birthday.name}`)
// 根据提醒类型执行不同策略
switch (reminder.type) {
case 'advance_notice':
// 提前通知 - 给用户准备时间
await this.showAdvanceNotice(birthday, reminder)
break
case 'preparation_reminder':
// 准备提醒 - 建议礼物、安排时间等
await this.showPreparationReminder(birthday)
break
case 'immediate_alert':
// 即时提醒 - 今天就是生日!
await this.showImmediateAlert(birthday)
break
case 'follow_up':
// 后续跟进 - 确认是否已祝福
await this.showFollowUpReminder(birthday)
break
}
}
// 显示智能准备建议
private async showPreparationReminder(birthday: BirthdayEvent) {
const suggestions = await this.generatePreparationSuggestions(birthday)
const notification = {
title: `🎁 ${birthday.name}的生日快到了!`,
content: `还有${this.getDaysUntilBirthday(birthday)}天,以下是一些建议:\n${suggestions.join('\n')}`,
actions: [
{ text: '查看祝福建议', action: () => this.showGreetingSuggestions(birthday.friendId) },
{ text: '设置提醒', action: () => this.setCustomReminder(birthday.friendId) },
{ text: '暂时忽略', action: () => this.snoozeReminder(birthday.friendId) }
]
}
this.showNotification(notification)
}
// 生成准备建议
private async generatePreparationSuggestions(birthday: BirthdayEvent): Promise<string[]> {
const relationshipData = this.relationshipAnalysis.get(birthday.friendId)
const suggestions: string[] = []
if (relationshipData?.level >= 7) {
suggestions.push('🎁 考虑准备一份特别的礼物')
suggestions.push('📞 提前约个时间见面庆祝')
}
if (birthday.preferences.hobbies.length > 0) {
const hobby = birthday.preferences.hobbies[0]
suggestions.push(`🎯 结合TA的爱好"${hobby}"选择祝福方式`)
}
if (relationshipData?.preferredContactMethod === 'social_media') {
suggestions.push('📱 准备一条特别的朋友圈祝福')
}
return suggestions
}
// 生日数据分析和洞察 - 让用户了解自己的社交模式
generateSocialInsights(): SocialInsights {
console.log('📊 生成社交洞察报告')
const insights: SocialInsights = {
totalFriends: this.upcomingBirthdays.length,
averageRelationshipLevel: this.calculateAverageRelationshipLevel(),
mostActiveMonth: this.findMostActiveBirthdayMonth(),
greetingSuccessRate: this.calculateGreetingSuccessRate(),
personalityDistribution: this.analyzePersonalityDistribution(),
improvementSuggestions: this.generateImprovementSuggestions()
}
return insights
}
// 工具方法们
private generateId(): string {
return Date.now().toString() + Math.random().toString(36).substr(2, 9)
}
private getDaysUntilBirthday(birthday: BirthdayEvent): number {
const today = new Date()
const thisYear = today.getFullYear()
const birthdayThisYear = new Date(thisYear, birthday.birthday.getMonth(), birthday.birthday.getDate())
if (birthdayThisYear < today) {
birthdayThisYear.setFullYear(thisYear + 1)
}
return Math.ceil((birthdayThisYear.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
}
private shouldTriggerReminder(reminder: ReminderConfig, now: Date): boolean {
// 复杂的时间匹配逻辑
return reminder.triggerTime <= now && !reminder.triggered
}
// 更多方法...
private loadBirthdayData() { /* 加载生日数据 */ }
private updateUpcomingBirthdays() { /* 更新即将到来的生日 */ }
private saveBirthdayEvent(event: BirthdayEvent) { /* 保存生日事件 */ }
private findBirthdayEvent(friendId: string): BirthdayEvent | null { return null }
private showNotification(notification: any) { /* 显示通知 */ }
// ... 更多辅助方法
}
// 相关数据类型定义
interface BirthdayEvent {
id: string
friendId: string
name: string
birthday: Date
avatar?: string
relationshipLevel: number
lastGreeting?: GreetingRecord
greetingHistory: GreetingRecord[]
preferences: FriendPreferences
reminderStrategy?: ReminderStrategy
}
interface RelationshipData {
level: number // 1-10 亲密度等级
contactFrequency: number
recentInteractions: InteractionRecord[]
preferredContactMethod: string
visualPreference: boolean
humorLevel: number
}
interface PersonalizedGreeting {
content: GreetingContent
mediaType: MediaType
optimalSendTime: Date
confidence: number
alternatives: GreetingContent[]
}
type MediaType = 'short_text' | 'long_text' | 'voice_message' | 'video_message' | 'custom_image' | 'meme'
// AI组件类(简化版)
class PersonalityAnalyzer {
async analyzeSocialPattern() { /* 分析社交模式 */ }
async analyzeRelationship(friendInfo: FriendInfo): Promise<RelationshipData> {
// 模拟AI分析
return {
level: Math.floor(Math.random() * 10) + 1,
contactFrequency: Math.random() * 100,
recentInteractions: [],
preferredContactMethod: 'text',
visualPreference: Math.random() > 0.5,
humorLevel: Math.floor(Math.random() * 10) + 1
}
}
}
class GreetingGenerator {
async learnUserStyle() { /* 学习用户祝福风格 */ }
async generateGreeting(params: any): Promise<GreetingContent> {
// 模拟AI生成祝福内容
return {
text: `生日快乐,${params.friendName}!🎂`,
tone: 'warm',
confidence: 85,
alternatives: []
}
}
}
class OptimalTimingCalculator {
async analyzeUserBehavior() { /* 分析用户行为模式 */ }
async calculateStrategy(birthday: BirthdayEvent, relationship: RelationshipData): Promise<ReminderStrategy> {
// 模拟计算提醒策略
return {
reminders: [
{
type: 'advance_notice',
triggerTime: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000), // 3天前
triggered: false
}
]
}
}
async calculateOptimalTime(friendId: string): Promise<Date> {
return new Date(Date.now() + 60 * 60 * 1000) // 1小时后
}
}
// 更多接口定义...
interface FriendInfo {
id: string
name: string
birthday: Date
avatar?: string
favoriteColors?: string[]
hobbies?: string[]
personalityTags?: string[]
}
interface GreetingContent {
text: string
tone: string
confidence: number
alternatives: GreetingContent[]
}
interface ReminderStrategy {
reminders: ReminderConfig[]
}
interface ReminderConfig {
type: 'advance_notice' | 'preparation_reminder' | 'immediate_alert' | 'follow_up'
triggerTime: Date
triggered: boolean
}
// 更多类型定义...
class ReminderSettings { /* 提醒设置 */ }
interface FriendPreferences { /* 朋友偏好 */ }
interface GreetingRecord { /* 祝福记录 */ }
interface InteractionRecord { /* 互动记录 */ }
interface SocialInsights { /* 社交洞察 */ }
看到这个庞大的智能生日助手系统了吗?这就是我在那个创意迸发的夜晚构思并开始实现的项目!AI个性化分析、智能祝福生成、最佳时机计算...每一个功能都让我兴奋不已。
那个晚上,我就像着了魔一样,代码一写就停不下来。脑子里不断涌现新的想法:"这里可以加个情感分析"、"那里可以用机器学习优化"、"还能加个社交网络分析功能"...
凌晨四点的时候,我已经写了上千行代码,搭建了整个系统的核心架构。虽然很多AI功能只是框架,但整个创意的实现路径已经非常清晰了。
那种纯粹的创造快乐,让我完全忘记了疲劳。每实现一个功能,心里就更加激动:"哇,这个功能太酷了!用户一定会喜欢的!"
天亮的时候,我看着屏幕上这个智能生日助手的雏形,内心充满了成就感和期待。虽然还有很多功能需要完善,但这个创意的种子已经种下了。
后来我花了两个月时间不断完善这个应用,最终它成了我最骄傲的作品之一。不仅功能强大,用户体验也特别好,甚至有几个朋友主动要求帮我推广。
这就是灵感驱动的熬夜——不是被迫的,而是主动的;不是痛苦的,而是快乐的。当创意的火花点燃时,那种创作的热情会让你忘记一切,只想把心中的想法完美地实现出来。
🌟 结语:那些深夜里闪闪发光的代码
写到这里,回想起这些年为鸿蒙开发熬过的那些夜,心里五味杂陈。有疲惫,有焦虑,有挫败,但更多的是满足、成就和对技术的纯粹热爱。
每一个深夜都有它独特的意义:第一个深夜教会我坚持和耐心,第二个深夜让我学会了严谨和细致,第三个深夜锻炼了我的抗压能力和效率,第四个深夜培养了我对完美的追求,第五个深夜释放了我的创造激情。
虽然熬夜不是什么值得推崇的习惯(现在的我已经在努力调整作息了),但那些深夜时光确实是我成长路上最珍贵的经历。在那些安静的夜里,没有白天的喧嚣和打扰,只有你和代码,只有问题和解决方案,只有想法和实现。
那种纯粹的专注感,那种与技术对话的感觉,那种创造出新功能时的兴奋...这些都是深夜开发独有的魅力。虽然身体疲惫,但精神充实;虽然黑眼圈很重,但内心满足。
现在当我看到那些在深夜里写出来的代码时,总会想起当时的情景:昏黄的台灯、浓郁的咖啡、敲击键盘的声音、还有那颗为了解决问题而跳动不已的心。
对了,想起一个有趣的细节。我有个习惯,喜欢在深夜写代码时给变量取一些特别的名字,比如midnightSolution
(午夜解决方案)、coffeeCounter
(咖啡计数器)、sleepyButDetermined
(困但坚定)...这些名字现在看起来很幽默,但它们记录了那些深夜的真实状态。
最后想对所有还在深夜敲代码的鸿蒙开发者们说:记得照顾好自己的身体,适度熬夜,多喝水,保护好眼睛。但如果某个夜晚,你被一个技术问题或者一个创意想法深深吸引,忍不住想要熬夜实现它——那就勇敢地去做吧!
因为这些深夜时光,会成为你技术路上最独特的回忆,会成为你成长历程中最宝贵的财富。那些在黑夜中闪闪发光的代码,承载着我们对技术的热爱,记录着我们成长的足迹。
愿所有的深夜都有意义,愿所有的努力都有回报,愿我们都能在鸿蒙开发的路上越走越远!
更多推荐
所有评论(0)