注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

早衰男的巢

大音希声 道隐无名

 
 
 

日志

 
 

Android: 让 widget 获取SharedPreferences的数据  

2014-07-19 01:16:24|  分类: android笔记 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

莫问动机,总而言之… 我需要让我的widget (AppWidgetProvider)去读取App之前已保存下来的SharedPreferences。

以照惯性思维最初设想的流程是这样的

widget 由两部分组成 一个是 AppWidgetProvider ,另一个是负责实现widget显示的信息的刷新的Service 。

用service刷新而不用widget配置文件自身的android:updatePeriodMillis属性, 是由于这个属性限制间隔不得小于30分钟,我想主要是出于电量续航和桌面UI的流畅性考虑。

最初的错误无效的的代码如下(省略了很多非关键的代码)

AppWidgetProvider

  1: public class myWidgetProvider extends AppWidgetProvider {
  2:   @Override
  3:   public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
  4:     SharedPreferences sp = context.getSharedPreferences(CFG_NAME,0);
  5:     String spVal= sp.getString("key", "0"); //读取 SharedPreferences 里的变量值
  6:     ......
  7:     
  8:     //启动service
  9:     Intent intent=new  Intent(context ,ServiceUpdateWidget. class );  
 10:     context.startService(intent);
 11: 	
 12:     super.onUpdate(context, appWidgetManager, appWidgetIds);
 13:   }
 14: }


Service

  1: public class ServiceUpdateWidget extends Service {
  2:   private AppWidgetManager appWidgetManager;
  3:   private ComponentName componentName;
  4:   private RemoteViews views;
  5:   private Timer timer;
  6:   private TimerTask task = new TimerTask() {
  7:     //定时器里循环执行的任务
  8:     //...各种改变widget views显示内容的业务逻辑
  9: 
 10:     // 更新widget
 11:     appWidgetManager.updateAppWidget(componentName, views);
 12:  }
 13: 
 14:   @Override
 15:   public void onCreate() {
 16:     super.onCreate();
 17:     
 18:     // 初始化widget管理器
 19:     appWidgetManager = AppWidgetManager.getInstance(context);
 20:     componentName = new ComponentName(context, myWidgetProvider.class); //widgetProvider
 21:     views = new RemoteViews(getPackageName(), R.layout.widget);
 22: 
 23:     //启动计时
 24:     timer = new Timer();
 25:     timer.schedule(task, 0, 10000);// 间隔10秒循环执行task		
 26:   }	
 27: 	
 28:   @Override
 29:   public void onDestroy() {
 30:     super.onDestroy();
 31:     timer.cancel();// 结束任务,注销timer
 32:   }
 33: }


运行..取出的数据是错的 spVal 的值是默认的“0”。开始了漫长的搜索解决方案之路。

有网志建议把Context.getSharedPreferences(CFG_NAME,SP_MODE); 的第二个参数设为 MODE_WORLD_READABLE。从字面含义都能理解这是个逗逼的主意,Google官方也从API5废弃这个方法建议开发者不要采用这种方式,存在明显的安全隐患(姑且不论安全的问题,这种方式仍然是取不出正确值的….)。
由于时间关系就直接讲答案 AppWidgetProvider 里的 onUpdate方法中的那个 context 不是它同一个包下Activity的context。

我开始钻这个牛角尖,寻找各种方法怎样能从widget上取得正确的context ,但这是一个 deadend。

stackoverflow的大牛对此盖棺定论:AppWidgetProvider is a subclass of BroadcastReceiver, which is not a Context.

【未经证实】网上有人给出解决办法 用 PreferenceManager.getDefaultSharedPreferences() 代替 Context.getSharedPreferences(CFG_NAME,SP_MODE);

这个方法也是有前提的,那就是存储 SharedPreferences 的时候 必须也用 getDefaultSharedPreferences() 也就是说 让 CFG_NAME 默认为包名。

我的天,我之前的代码已经有好多地方用了自定义的 CFG_NAME。 给自己挖下这么多坑我是改不回来了。这个方案放弃!

【我的解决办法】

思路都打结了,决定去洗个澡喝杯可乐……!

来灵感了!!艹…我钻什么牛角尖呢… Service 是一个Context啊…蠢死了!

在Service里添加一句

private Context context = this;

再把

SharedPreferences sp = context.getSharedPreferences(CFG_NAME,0);

插入 onCreate()。

把sp的数据在 service 读出来再用task 推到widget上显示..搞定。


好梦。

  评论这张
 
阅读(946)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018