天天看点

android开发之widget控件突然停止更新的原因

     在android中开发widget控件的时候在appwidget-provider元素中有个属性android:updatePeriodMillis控制widget控件多长时间刷新一次,但是在1.6以后的版本中,谷歌从省电的方面考虑规定,当updatePeriodMillis的设置的值小于半个小时时,就会失效。也就是通过设置这个属性值,最短的更新间隔是半小时。但是我们有时候做的一些应用,比如时钟之类的必须要在极端的时间内刷新,必须另辟蹊径。网上流传的大都是这么几种方法:

1通过自己发送android.appwidget.action.APPWIDGET_UPDATE这个广播刷新,但是他会使所有的桌面widget控件刷新

 2 通过自己发送自定义的广播刷新

关键在于在哪里发送广播,有这么几种选择

1在OnEnable中开启定时线程发

2单开一个service发

3用alarm定时发

后两种是可行的,第一种方法虽然看起来可行但是有一个bug,如果不解决就会发现自己的widget在运行了一段时间后莫名其妙的的停止了运行。我当时发现总是过一段时间莫名其妙的停止运行后很苦恼,找不到原因,但是系统每半小时的android.appwidget.action.APPWIDGET_UPDATE广播还是能正常启动,后来在全局的logcat里发现停止运行前有一个进程向widget的进程发送了一个信号,signal:9,经过查找后在linux进程通信中发现9号信号就是强制结束进程的信号,可是为什么总是向widget进程发送这个信号呢,后来想起来AppWidgetProvider是BroadCastReceiver继承过来的,而BroadCastReceiver的说明里有这么一段话:

BroadcastReceiver如果需要完成一项比较耗时的工作 , 应该通过发送 Intent 给 Service, 由 Service 来完成 . 这里不能使用子线程来解决 , 因为 BroadcastReceiver 的生命周期很短 , 子线程可能还没有结束

BroadcastReceiver 就先结束了 .BroadcastReceiver 一旦结束 , 此时 BroadcastReceiver 的

所在进程很容易在系统需要内存时被优先杀死 , 因为它属于空进程 ( 没有任何活动组件的进程 ). 如果它的宿主进程被杀死 , 那么正在工作的子线程也会被杀死 . 所以采用子线程来解决是不可靠的 。

关键原因在于widget所在进程属于没有活动组件的空进程,所以被杀,要想不被杀,是他拥有一个活动组件就行,比如service,虽然这样还会被杀死,但是比起之前2、3个小时就被杀掉一次的频率就小多了。而且可以提高service优先级。

综上所述要想而是用线程发送广播的方法来更新widget的同时要注意不能使得widget所在的进程成为空进程。不然非常容易被系统清理掉。