最近在项目里用到widget ,涉及到widget 的定时更新和事件监控与处理。具体效果如图:

功能:

实现定时更新

能展示同一组数据,update 时更新数据源

可以监听事件,并作出不同反应

实现分析:

SDK1.5 之后android:updatePeriodMillis 就失效,改为默认更新,为了实现自定义定时更新,用到了定时器主动更新;

widget 由其它应用程序托管,共用数据十分困难,我将数据写入sharedpreferences ,以记录数据源;

widget 各种状态都是由消息控制,为方便事件管理,向系统注册接受器。

首先在AndroidManifest.xml 文件中注册widget:

  1. <receiver
  2. android:name=".widget"
  3. android:label="@string/app_name"
  4. >
  5. <intent-filter>
  6. <actionandroid:name="android.appwidget.action.APPWIDGET_UPDATE"/>
  7. </intent-filter>
  8. <meta-data
  9. android:name="android.appwidget.provider"
  10. android:resource="@xml/widget"
  11. />
  12. </receiver>

添加res/xml/widget.xml设置widget属性:
  1. <appwidget-provider
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:minWidth="294dip"
  4. android:minHeight="72dip"
  5. android:updatePeriodMillis="5000"
  6. android:initialLayout="@layout/appwidget"
  7. >
  8. </appwidget-provider>

实现定时更新,只需在widget第一次创建或系统重启时开启计时器,于是给来自计时器的消息加上sheme以区分:
  • publicstaticfinalStringURI_SCHEME="widget";
  • publicvoidonReceive(Contextcontext,Intentintent){
  • if(AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(intent.getAction()))
  • finalint[]appWidgetIds=intent.getExtras().getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
  • for(intappWidgetId:appWidgetIds)
  • {
  • if(appWidgetId==AppWidgetManager.INVALID_APPWIDGET_ID)
  • continue;
  • //scheme不等于URI_SCHEME说明这个消息来自系统
  • //定时更新或是widget第一次创建或是系统重启
  • if(!URI_SCHEME.equals(intent.getScheme())){
  • setAlarm(context,appWidgetId,updateTime);
  • }
  • else{
  • //可以在这里修改更新时间,如果有必要
  • //例如:
  • //setAlarm(context,appWidgetId,theValueComeFromPreference
  • }
  • }
  • super.onReceive(context,intent);
  • }
  • }
    1. privatevoidsetAlarm(Contextcontext,intappWidgetId,intupdateRateSeconds){
    2. IntentwidgetUpdate=newIntent();
    3. widgetUpdate.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    4. widgetUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,newint[]{appWidgetId});
    5. //给来自计时器的消息加标识
    6. widgetUpdate.setData(Uri.withAppendedPath(Uri.parse(URI_SCHEME+"://widget/id/"),String.valueOf(appWidgetId)));
    7. PendingIntentnewPending=PendingIntent.getBroadcast(context,0,widgetUpdate,PendingIntent.FLAG_UPDATE_CURRENT);
    8. AlarmManageralarms=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    9. if(updateRateSeconds>=0){
    10. alarms.setRepeating(AlarmManager.ELAPSED_REALTIME,SystemClock.elapsedRealtime(),updateRateSeconds,newPending);
    11. }else{
    12. alarms.cancel(newPending);
    13. }
    14. }
    要接受来自计时器的消息,需要在AndroidManifest.xml另注册接受器:

    1. <receiver
    2. android:name=".widget"
    3. android:label="@string/app_name"
    4. >
    5. <intent-filter>
    6. <actionandroid:name="com.example.widget.APPWIDGET_UPDATE"/>
    7. <dataandroid:scheme="widget"/>
    8. </intent-filter>
    9. <meta-dataandroid:name="android.appwidget.provider"
    10. android:resource="@xml/widget"
    11. />
    12. </receiver>

    实现了定时更新。接下来展示界面:

    1. publicstaticfinalStringPREFS_NAME="com.example.widget_preferences";
    2. publicstaticfinalStringPREFS_WIDGET_DATA="WidgetData-%d";
    3. publicstaticfinalStringPREFS_CURRENT_INDEX="CurrentIndex-%d";
    4. privatestaticfinalStringACTION_WIDGET_CONTROL="com.example.widget.WIDGET_CONTROL";
    5. publicvoidonUpdate(Contextcontext,AppWidgetManagerappWidgetManager,
    6. int[]appWidgetIds){
    7. //TODOAuto-generatedmethodstub
    8. finalintN=appWidgetIds.length;
    9. SharedPreferencesshared=context.getSharedPreferences(PREFS_NAME,0);
    10. SharedPreferences.Editoreditor=shared.edit();
    11. for(inti=0;i<N;i++)
    12. {
    13. if(appWidgetIds[i]==AppWidgetManager.INVALID_APPWIDGET_ID)
    14. continue;
    15. intappWidgetId=appWidgetIds[i];
    16. StringwidgetDataStr=“data1=value|||data2=value|||data3=value|||data4=value”;
    17. editor.putString(String.format(PREFS_WIDGET_DATA,appWidgetIds[i]),widgetDataStr);
    18. editor.putInt(String.format(PREFS_CURRENT_INDEX,appWidgetIds[i]),0);
    19. updateDisplay(context,appWidgetId,getDataByKey(widgetDataStr,0));
    20. }
    21. editor.commit();
    22. }
    23. privateString[]getDataByKey(StringdataStr,intindex)
    24. {
    25. String[]strArr=dataStr.split("//|//|//|");
    26. if(index<0)
    27. index=0;
    28. if(index>=strArr.length)
    29. index=strArr.length-1;
    30. strArr=strArr[index].split("=",2);
    31. if(strArr.length==2)
    32. returnstrArr;
    33. returnnewString[]{"",""};
    34. }
    35. publicvoidupdateDisplay(Contextcontext,intappWidgetId,String[]playData)
    36. {
    37. RemoteViewsremoteView=newRemoteViews(context.getPackageName(),R.layout.appwidget);
    38. remoteView.setTextViewText(R.id.widget_word,playData[0]);
    39. remoteView.setTextViewText(R.id.widget_meaning,playData[1]);
    40. remoteView.setOnClickPendingIntent(R.id.widget_back,makeControlPendingIntent(context,"back",appWidgetId));
    41. remoteView.setOnClickPendingIntent(R.id.widget_next,makeControlPendingIntent(context,"next",appWidgetId));
    42. AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId,remoteView);
    43. }
    44. publicPendingIntentmakeControlPendingIntent(Contextcontext,Stringcommand,intappWidgetId)
    45. {
    46. Intentaction=newIntent();
    47. action.setAction(ACTION_WIDGET_CONTROL);
    48. action.putExtra(EXTRA_APPWIDGET_ID,appWidgetId);
    49. Uridata=Uri.withAppendedPath(Uri.parse(URI_SCHEME+"://widget/id/#"+command),String.valueOf(appWidgetId));
    50. action.setData(data);
    51. return(PendingIntent.getBroadcast(context,0,action,PendingIntent.FLAG_ONE_SHOT));
    52. }

    这样widget就可以正常显示了,当然,现在还无法接受消息去处理事件,接下来注册接受器:

            
    1. <receiver
    2. android:name=".widget"
    3. android:label="@string/app_name"
    4. >
    5. <intent-filter>
    6. <actionandroid:name="com.example.widget.WIDGET_CONTROL" />
    7. <dataandroid:scheme="widget"/>
    8. </intent-filter>
    9. <meta-dataandroid:name="android.appwidget.provider"
    10. android:resource="@xml/widget"
    11. />
    12. </receiver>
    然后,处理不同命令:
    1. publicvoidonReceive(Contextcontext,Intentintent)
    2. if(ACTION_WIDGET_CONTROL.equals(action))
    3. {
    4. finalintappWidgetId=intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);
    5. if(appWidgetId!=AppWidgetManager.INVALID_APPWIDGET_ID)
    6. {
    7. StringcontrolType=intent.getData().getFragment();
    8. SharedPreferencesshared=context.getSharedPreferences(PREFS_NAME,0);
    9. intindex=shared.getInt(String.format(PREFS_CURRENT_INDEX,appWidgetId),0);
    10. intsize=Integer.parseInt(shared.getString(String.format(PREFS_DATA_SIZE,appWidgetId),"20"));
    11. if(controlType.equalsIgnoreCase("next"))
    12. {
    13. index++;
    14. if(index>=size)
    15. index=0;
    16. }
    17. elseif(controlType.equalsIgnoreCase("back"))
    18. {
    19. index--;
    20. if(index<0)
    21. index=size-1;
    22. }
    23. shared.edit().putInt(String.format(PREFS_CURRENT_INDEX,appWidgetId),index).commit();
    24. updateDisplay(
    25. context,
    26. appWidgetId,
    27. getDataByKey(shared.getString(String.format(PREFS_WIDGET_DATA,appWidgetId),""),index)
    28. );
    29. }
    30. }
    31. }
    32. 最后,不能忘了收尾工作:
    33. publicvoidonDeleted(Contextcontext,int[]appWidgetIds){
    34. //TODOAuto-generatedmethodstub
    35. SharedPreferencesshared=context.getSharedPreferences(PREFS_NAME,0);
    36. for(intappWidgetId:appWidgetIds)
    37. {
    38. setAlarm(context,appWidgetId,-1);
    39. shared.edit().remove(String.format(PREFS_WIDGET_DATA,appWidgetId))
    40. .remove(String.format(PREFS_CURRENT_INDEX,appWidgetId))
    41. .commit();
    42. }
    43. super.onDeleted(context,appWidgetIds);
    44. }




    更多相关文章

    1. android之handler介绍和使用方法
    2. [移动] Android推送方案分析(MQTT/XMPP/GCM)
    3. Android(安卓)推送实现原理解析
    4. Android推送通知的实现--采用MQTT协议实现Android消息推送
    5. Android文件上传下载
    6. Android(安卓)Studio实现一个PC和Android端的聊天室
    7. Android(安卓)Looper用法及原理
    8. Android(安卓)第九天(晚上)
    9. Android用户事件输入路径

    随机推荐

    1. Android的ListView控件滚动时背景问题
    2. Android(一) 安卓概述
    3. Android(安卓)Mac开发Android推荐软件
    4. Android(安卓)应用程序(APK) 如何获得系
    5. android:layout_paddingLeft和android:la
    6. Android(安卓)应用程序基础
    7. Android学习及如何利用android来赚钱
    8. Android引路蜂地图开发包
    9. Android的Camera架构介绍
    10. Android面试题总结(一)