import Toybox.Application; import Toybox.Background; import Toybox.Lang; import Toybox.System; import Toybox.Time; import Toybox.WatchUi; import Owm; // ============================================================================ // 应用入口 // ---------------------------------------------------------------------------- // 表盘没有菜单也拿不到输入,所以这个壳子只做三件事: // 1. 交出 view // 2. 设置变更时请求重绘 // 3. 管理拉取 OpenWeatherMap 的后台服务 // ============================================================================ class Fenix8V3App extends Application.AppBase { // OWM 免费档的调用额度很宽裕,但表盘每分钟才重绘一次、数据本身也是小时级的, // 拉太勤只是白白唤醒射频费电。半小时是个合适的折中。 const OWM_PERIOD_MIN = 30; function initialize() { AppBase.initialize(); } function onStart(state as Dictionary?) as Void { } function onStop(state as Dictionary?) as Void { } // ⚠️ 定时器的注册必须放在 getInitialView 里,不能放 onStart。 // 因为 onStart **在后台服务进程里也会被调用一次**,而在后台进程里调 // registerForTemporalEvent 会抛 Out of Bounds。 // getInitialView 只在前台进程运行,是安全的位置。 function getInitialView() as [Views] or [Views, InputDelegates] { scheduleWeather(); return [new Fenix8V3View()]; } function getServiceDelegate() as [System.ServiceDelegate] { return [new Fenix8V3Background()]; } // 只有用户真的填了 API key 才注册定时器 —— 没填就没什么可拉的, // 注册了纯属浪费电。反过来,用户把 key 清空时也要及时注销。 function scheduleWeather() as Void { if (!(Background has :registerForTemporalEvent)) { return; } // ⚠️ deleteTemporalEvent 在「本来就没注册」时会抛 Out of Bounds, // 而这个错误是 VM 级的,**try/catch 抓不住**。 // 所以这里不去问系统当前状态,而是自己在 Storage 里记一个标志位。 // 重复注册本身是无害的(只是重置周期),所以只在状态真的变化时动手。 var want = Owm.enabled(); var have = Application.Storage.getValue("bgOn"); have = (have != null) && (have as Boolean); if (want == have) { return; } if (want) { Background.registerForTemporalEvent( new Time.Duration(OWM_PERIOD_MIN * 60)); } else { Background.deleteTemporalEvent(); } Application.Storage.setValue("bgOn", want); } // 手机把新设置推下来时触发。 // view 每次绘制都是现读设置,所以重绘一下就够了; // 但天气定时器要跟着新的 key 状态启停,所以先过一遍 scheduleWeather。 function onSettingsChanged() as Void { scheduleWeather(); WatchUi.requestUpdate(); } // 后台服务把结果通过这里交回前台。存进 Storage 供表盘读取,然后重绘。 function onBackgroundData(data as Application.PersistableType) as Void { if (data != null) { Application.Storage.setValue(Owm.STORE, data); WatchUi.requestUpdate(); } } } function getApp() as Fenix8V3App { return Application.getApp() as Fenix8V3App; }