Android widget定时更新及事件处理

最近在项目里用到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.             <action android: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属性:
    • <appwidget-provider
    •         xmlns:android="http://schemas.android.com/apk/res/android"
    •         android:minWidth="294dip"
    •         android:minHeight="72dip"
    •         android:updatePeriodMillis="5000"      
    •         android:initialLayout="@layout/appwidget"
    •         >
    • </appwidget-provider>

实现定时更新,只需在widget第一次创建或系统重启时开启计时器,于是给来自计时器的消息加上sheme以区分:
  • public static final String URI_SCHEME = "widget";
  • public void onReceive(Context context, Intent intent) {
  •         if(AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(intent.getAction()))
  •        
  •                 final int[] appWidgetIds = intent.getExtras().getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
  •                 for (int appWidgetId : 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);
  •  

  •         }
  •  

  • }
      • private void setAlarm(Context context, int appWidgetId, int updateRateSeconds) {
      •         Intent widgetUpdate = new Intent();
      •         widgetUpdate.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
      •         widgetUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { appWidgetId });
      •         //给来自计时器的消息加标识
      •         widgetUpdate.setData(Uri.withAppendedPath(Uri.parse(URI_SCHEME + "://widget/id/"), String.valueOf(appWidgetId)));
      •         PendingIntent newPending = PendingIntent.getBroadcast(context, 0, widgetUpdate, PendingIntent.FLAG_UPDATE_CURRENT);
      •         AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
      •         if (updateRateSeconds >= 0) {
      •                 alarms.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), updateRateSeconds, newPending);
      •         } else {
      •                 alarms.cancel(newPending);
      •         }
      • }
    要接受来自计时器的消息,需要在AndroidManifest.xml另注册接受器:

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

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

    1. public static final String PREFS_NAME = "com.example.widget_preferences";
    2. public static final String PREFS_WIDGET_DATA = "WidgetData-%d";
    3. public static final String PREFS_CURRENT_INDEX = "CurrentIndex-%d";
    4. private static final String ACTION_WIDGET_CONTROL = "com.example.widget.WIDGET_CONTROL";
    5. public void onUpdate(Context context, AppWidgetManager appWidgetManager,
    6.             int[] appWidgetIds) {
    7.         // TODO Auto-generated method stub
    8.         final int N = appWidgetIds.length;
    9.         SharedPreferences shared = context.getSharedPreferences(PREFS_NAME, 0);
    10.         SharedPreferences.Editor editor = shared.edit();
    11.         for(int i = 0; i < N; i++)
    12.         {
    13.                 if(appWidgetIds[i] == AppWidgetManager.INVALID_APPWIDGET_ID)
    14.                         continue;
    15.                 int appWidgetId = appWidgetIds[i];
    16.                 String widgetDataStr = “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. private String[] getDataByKey(String dataStr, int index)
    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.                 return strArr;
    33.         return new String[]{"",""};
    34. }
    35. public void updateDisplay(Context context, int appWidgetId, String[] playData)
    36. {
    37.         RemoteViews remoteView = new RemoteViews(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. public PendingIntent makeControlPendingIntent(Context context, String command, int appWidgetId)
    45. {
    46.         Intent action = new Intent();
    47.         action.setAction(ACTION_WIDGET_CONTROL);
    48.         action.putExtra(EXTRA_APPWIDGET_ID, appWidgetId);
    49.         Uri data = 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.                 <action android:name="com.example.widget.WIDGET_CONTROL"  />
    7.                 <data android:scheme="widget" />
    8.         </intent-filter>
    9.         <meta-data android:name="android.appwidget.provider"
    10.                 android:resource="@xml/widget"
    11.                 />
    12. </receiver>
    然后,处理不同命令:
    1. public void onReceive(Context context, Intent intent)
    2. if(ACTION_WIDGET_CONTROL.equals(action))
    3. {
    4.         final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
    5.         if(appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID)
    6.         {
    7.                 String controlType = intent.getData().getFragment();
    8.                 SharedPreferences shared = context.getSharedPreferences(PREFS_NAME, 0);
    9.                 int index = shared.getInt(String.format(PREFS_CURRENT_INDEX, appWidgetId), 0);
    10.                 int size = 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.                 else if(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. public void onDeleted(Context context, int[] appWidgetIds) {
    34.         // TODO Auto-generated method stub
    35.         SharedPreferences shared = context.getSharedPreferences(PREFS_NAME, 0);
    36.         for(int appWidgetId : 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. }




     

     

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值