经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » iOS » 查看文章
IOS Widget(5):小组件刷新机制
来源:cnblogs  作者:popfisher  时间:2021/5/10 22:34:12  对本文有异议

引言

前面的章节学完已经让我们可以顺利实现一个小组件了,但是小组件里面的数据如何刷新的呢,本节内容将讲解IOS的刷新机制。

大纲

  • 系统如何管理小组件刷新
  • Timeline刷新机制
  • Timeline刷新机制代码实现
  • 刷新策略建议
  • 时钟刷新策略(只有小时分钟,没有秒)
  • 主动请求重新刷新

系统如何管理小组件刷新

  1. WidgetKit在一个单独的进程中渲染小组件视图
  2. 即使小组件窗口显示在屏幕上,widget extension 也不会持续处于活动状态
  3. 为了管理系统负载,WidgetKit使用预算来分配一天中的窗口小组件重载
  4. WidgetKit为用户添加到其设备的每个活动小组件维护不同的预算
  5. 每日预算通常包括40到70次刷新。该速率大致可转换为小组件每15至60分钟重新加载一次,但是由于涉及到许多因素,因此这些时间间隔是不固定的。

综上所述,小组件的刷不能由开发者自由控制,官方建议如下:

  1. 如果您的小组件可以预测应重新加载的时间点,则最好的方法是为尽可能多的将来日期生成时间线。
  2. 时间轴中的条目间隔应保持尽可能大。
  3. 时间轴应创建至少相隔5分钟的时间轴条目。
  4. WidgetKit可能会在多个窗口小组件之间合并重新加载,从而影响窗口小组件重新加载的确切时间。

Timeline刷新机制


该图显示了WidgetKit请求时间线,提供程序生成时间线以及3小时后的时间进度,之后WidgetKit请求新的时间线


该图显示了WidgetKit请求时间线,提供程序生成时间线以及WidgetKit在2小时后请求新时间线的图

Timeline刷新机制代码实现(新增组件时,系统默认就实现了)

  1. func getTimeline(for configuration: TimeTypeConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
  2.     var entries: [SimpleEntry] = []
  3.     // Generate a timeline consisting of five entries an hour apart, starting from the current date.
  4.     let currentDate = Date()
  5.     for hourOffset in 0 ..< 5 {
  6. // 下面这个代码表示,在当前日期上加上 hourOffset 个小时得到一个新的日期
  7. // .hour可以换成 .second .minute .day 等
  8.         let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
  9.         let entry = SimpleEntry(date: entryDate, configuration: configuration)
  10.         entries.append(entry)
  11.     }
  12. // 调用回调方法把生成好的时间线数据传递给系统
  13. // policy 表示刷新策略
  14. // .atEnd 表示,所有的时间线条目完成之后重新刷新一次,表现就是这个getTimeline方法被回调一次
  15. // .after(date: Date) 表示,多久时间结束后再刷新一次
  16. // .never表示时间轴走完就不刷了
  17.     let timeline = Timeline(entries: entries, policy: .atEnd)
  18.     completion(timeline)
  19. }

备注:
??网上大部分资料都写着Timeline时间轴相隔5分钟,即每次创建5分钟内的刷新条目,但是小组件预算每日40到70次刷新,假设按70次算,总时间70 * 5 = 350分钟,大约6个小时就把次数用完了。所以大部分情况5分钟的间隔确实可以满足了,但是难免还是有用户把这个限制次数用完了。保险起见,尽量把时间间隔扩大,如果内存消耗不大,可以把间隔控制在60分钟,时间轴上每个条目间隔1分钟。这样几乎不会把系统给小组件的预算刷新次数给用完。

正是因为IOS系统对小组件有刷新次数有限制和内存方面的限制(官网没有找到,但是看到网友们说是30M左右的限制,自己使用过程中也发现了占用内存过多导致进程被挂起,小组件就展示不出来了),所以没控制好刷新策略的话,可能经常会出现小组件界面展示不出来,或者过了一段时间之后,小组件直接不刷新了。

刷新策略建议

  1. 每次刷新时,时间轴准备好15-60分钟的刷新数据,最少是5分钟
  2. 时间轴每个刷新条目时间间隔尽可能大,时钟内组件间隔可以设置为1分钟
  3. 条目数量不宜过多,越少越好,时钟组件最多60左右
  4. 不要在5分钟内创建300个条目来做时钟按秒刷新,大概率会失败

时钟刷新策略(只有小时分钟,没有秒)

  1. static func prepareEntriesEveryMinute(_ completion: @escaping (Timeline<WidgetEntry>) -> ()) {
  2.     // 第一次刷新时间:延迟2秒刷
  3.     let firstDate = Provider.getFirstEntryDate()
  4.     // 第二次刷新时间:第一个整分钟时刷
  5.     let firstMinuteDate = Provider.getFirstMinuteEntryDate()
  6.    
  7.     var entries: [WidgetEntry] = []
  8.     entries.append(WidgetEntry(date: firstDate))
  9.     entries.append(WidgetEntry(date: firstMinuteDate))
  10.    
  11.     // 后面以第一个整点分钟开始,每次加一分钟刷
  12.     for minuteOffset in 1 ..< 60 {
  13.         guard let entryDate = Calendar.current.date(byAdding: .minute, value: minuteOffset, to: firstMinuteDate) else {
  14.             continue
  15.         }
  16.         entries.append(WidgetEntry(date: entryDate))
  17.     }
  18.     let timeline = Timeline(entries: entries, policy: .atEnd)
  19.     completion(timeline)
  20. }
  21. static func getFirstEntryDate() -> Date {
  22.     let offsetSecond: TimeInterval = TimeInterval(2)
  23.     var currentDate = Date()
  24.     currentDate += offsetSecond
  25.     return currentDate
  26. }
  27. // 获取第一个分钟时间点所处的时间点
  28. static func getFirstMinuteEntryDate() -> Date {
  29.     var currentDate = Date()
  30.     let passSecond = Calendar.current.component(.second, from: currentDate)
  31.     let offsetSecond: TimeInterval = TimeInterval(60 - passSecond)
  32.     currentDate += offsetSecond
  33.     return currentDate
  34. }

主动请求重新刷新

如果在App中修改了小组件的数据,可以通过如下的方式主动触发WidgetKit刷新小组件。

  1. // 指定刷新哪个组件
  2. WidgetCenter.shared.reloadTimelines(ofKind: "com.mygame.character-detail")
  3. // 刷新全部组件
  4. WidgetCenter.shared.reloadAllTimelines()

结语

小组件的刷新,官方文档都没有明确说明到底是什么具体的规则,只说了有各种限制,系统会动态管理。所以在实际开发中可能会遇到小组件数据不刷新的问题,遇到这种情况,请减少Timeline中的条目数量,优化内存,确保小组件代码里面没有异常。小组件运行在单独的进程,如果异常会导致小组件进程卡死了,一个小组件出问题,其他小组件都不刷新了。既然刷新这么难控制,怎么实现数字时钟按秒刷新呢?下一节揭晓。

原文链接:http://www.cnblogs.com/popfisher/p/14752842.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号