PixelUI 把时间输入、状态更新和 framebuffer 提交分开,但除一个很窄的 ISR 入口外,所有 UI 操作都属于同一 UI task。
调度入口
| API | 作用 |
|---|---|
heartbeat(elapsedMs) |
在普通上下文加入真实经过的毫秒数 |
tickFromISR(elapsedMs) |
在定时 ISR 原子累加时间,并可合并唤醒 UI task |
process() |
消费时间,更新到期的 deadline source、Animation、Popup 和 Coroutine |
renderer() |
先调用 process(),再在 dirty、fade 或 continuous draw 时提交帧 |
handler(frameIntervalMs) |
运行一次完整调度,并返回下次唤醒延时 |
heartbeat() 和 tickFromISR() 只选一条时间来源,混用会重复计时。process() 的返回值只表示消费了 elapsed time;renderer() 返回值才表示实际提交了一帧。
Dirty 合并
1 | sensorValue = newValue; |
markDirty() 把 clean 状态变为 dirty。连续多次调用只需要一次唤醒。setRenderRequestCallback() 应只发通知,不能在状态变更调用栈中同步重入 renderer()。
RTOS 任务边界
1 | timer ISR: tickFromISR() ----+ |
Widget setter、handleInput()、markDirty()、Popup、Animation 和 ViewManager 导航都必须在 UI task 中调用。定时 ISR 可使用 setTaskNotifyFromISR() 配置的平台回调唤醒它。配置应在开启中断前完成,中断可运行时不要替换回调或 context。
周期与 tickless [试验性] [EXPERIMENTAL]
PIXELUI_ENABLE_TICKLESS=0 时,handler() 总是返回主机给定的周期。开启 tickless 后,它会合并已注册 deadline source(例如 BlinkState)、Animation、Popup、Coroutine 和 fade 的 deadline,并返回其中最早者;0 表示应立即再运行一次,PixelUI::WAIT_FOREVER 表示可停止 UI 定时器,直到外部事件唤醒。
UiDeadlineScheduler 用于接入这种“到某个时刻才发生一次离散状态变化”的对象。source 在构造/析构时自动注册/注销,调度器只在到期时调用它,并由实际状态变化决定是否标记 dirty。它不应替代连续动画。
返回的 delay 不会取代外部事件通知。低功耗移植需要同时处理“时间 deadline”和“输入/数据到达”两类唤醒。
状态查询
nextWakeupMs(periodicTickMs):只查询下次唤醒延时,不更新也不绘制。needsHeartbeat():表示仍有时间驱动工作,不等于当前已有一帧待画。hasPendingFrame():表示当前有 dirty、fade 或 continuous frame,不代表未来没有 deadline。
setContinuousDraw(true) 只用于状态必须逐帧推进、无法用 dirty 或 deadline 表达的画面。普通动画和 BlinkState 都不需要它。
