android之widget详解

我会带着你远行 2022-09-19 01:47 282阅读 0赞

首先来看一个很简单的widget实现 http://blog.csdn.net/y13872888163/article/details/6346723

widget与app交互例子http://my.eoe.cn/665829/archive/2166.html

让自己的android应用支持appwidget

如何在自己的程序中添加appwidget

Android API开发指南中的App Widgets 有官方网站关于widget的介绍。

同一个Widget部件可以同时创建多个。

1、首先需要提供一个定义了Widget界面布局的XML文件(位于res/layout/..),需要注意的是使用的组件必须是RemoteViews所支持的,目前原生API中支持的组件如下:
FrameLayout
LinearLayout
RelativeLayout
AnalogClock
Button
Chronmeter
ImageButton
ImageView
ProgressBar
TextView

*如果使用了除此之外的组件,则在Widget创建时会导致android.view.InflateExceptionn异常。

2、新建AppWidgetProvderInfo。也就是提供一个xml文件来定义Widget的基本属性,放置到res/xml/..目录下。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:minWidth="80dp"
  4. android:minHeight="32dp"
  5. android:updatePeriodMillis="86400000"
  6. android:initialLayout="@layout/widget_provider"
  7. android:configure="com.demo.widget.MyWidgetConfiguration" >
  8. </appwidget-provider>

minWidth: 定义Wdiget组件的宽度
minHeight: 定义Wdiget组件的高度
updatePeriodMillis: 更新的时间周期
initialLayout:指定桌面组件的布局文件
configure: 如果需要在启动前先启动一个Activity进行设置,在这里给出Activity的完整类名(后面会说到,与一般Activity的实现有些许差别)

3、接下来就是创建一个继承自AppWidgetProvider的子类,AppWidgetProvider实际上就是一个BroadcastReceiver,里面提供了以下函数:

onReceive(Context, Intent)
onUpdate(Context , AppWidgetManager, int[] appWidgetIds)
onEnabled(Context)
onDeleted(Context, int[] appWidgetIds)
onDisabled(Context)
可通过重写以上函数来监听Widget状态的变化并进行相应的处理。

  1. public class MyAppWidgetProvider extends AppWidgetProvider {
  2. private static final String CLICK_NAME_ACTION = "com.terry.action.widget.click";
  3. public static final String TAG = "widget";
  4. public static RemoteViews rv;
  5. /**
  6. * 更新(Widget的更新与Activity不同,必须借助于RemoteViews和AppWidgetMananger。)
  7. */
  8. public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
  9. Log.i(TAG, "onUpdate");
  10. int N = appWidgetIds.length; // 可能启动了多个Widget,appWidgetIds记录了这些Widget的ID
  11. for(int i=0; i<N; i++){
  12. int appWidgetId = appWidgetIds[i];
  13. rv = new RemoteViews(context.getPackageName(), R.layout.main);
  14. Intent intentClick = new Intent(CLICK_NAME_ACTION);
  15. PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
  16. intentClick, 0);
  17. rv.setOnClickPendingIntent(R.id.TextView01, pendingIntent);
  18. appWidgetManager.updateAppWidget(appWidgetId, rv);
  19. }
  20. }
  21. /**
  22. * 第一个Widget组件启动时触发
  23. */
  24. public void onEnabled(Context context){
  25. Log.i(TAG, "onEnabled");
  26. }
  27. /**
  28. * 最后一个Widget组件关闭时触发
  29. */
  30. public void onDisabled(Context context){
  31. Log.i(TAG, "onDisabled");
  32. }
  33. /**
  34. * 任一Widget组件被删除时触发
  35. */
  36. public void onDeleted(Context context, int[] appWidgetIds){
  37. Log.i(TAG, "onDeleted");
  38. }
  39. /**
  40. * 以上函数触发前会先触发该函数,一般不需要重写
  41. */
  42. public void onReceive(Context context, Intent intent){
  43. Log.i(TAG, "onReceive");
  44. super.onReceive(context, intent);
  45. if (rv == null) {
  46. rv = new RemoteViews(context.getPackageName(), R.layout.main);
  47. }
  48. if (intent.getAction().equals(CLICK_NAME_ACTION)) {
  49. rv.setTextViewText(R.id.TextView01, context.getResources()
  50. .getString(R.string.load));
  51. }
  52. AppWidgetManager appWidgetManger = AppWidgetManager.getInstance(context);
  53. int[] appIds = appWidgetManger.getAppWidgetIds(new ComponentName(context, widgetProvider.class));
  54. appWidgetManger.updateAppWidget(appIds, rv);
  55. }
  56. }

其中需要注意的是,虽然RemoteViews参数都是一样的,但是对于每个Widget最好都新创建一个再进行传递,否则会导致一些错误。具体可参考AppWidget RemoteViews 内存溢出 。

其他函数的可以根据需要实现。

由于无法获取到RemoteViews创建的界面中的元素,对于Widget中组件的操作只能通过RemoteViews所提供的有限的函数进行,常用的有:
setOnClickPendingIntent(int viewId, PendingIntent pendingIntent)
setProgressBar(int viewId, int max, int progress, boolean indeterminate)
setTextViewText(int viewId, CharSequence text)
setViewVisibility(int viewId, int visibility)
详细函数列表可参考API中的RemoteViews类

4、最后,更新AndroidManifest.xml。

  1. <receiver android:name="MyWidgetProvider">
  2. <intent-filter>
  3. <action android:name="android.appwidget.action.APPWIDGET_UPDATE"></action>
  4. <action android:name="com.terry.action.widget.click"></action>
  5. </intent-filter>
  6. <meta-data android:resource="@xml/widget_property" android:name="android.appwidget.provider"></meta-data>
  7. </receiver>

5、 提供Configuration Activity
Configuration Activity是一个在Widget启动前先启动的Activity,方便用户对Widget的属性进行设置。

在res/xml/…下对应的”属性文件”中添加configure字段指定启动的Activity,并在AndroidManifest.xml中该Activity下提供一个action为android.appwidget.action.APPWIDGET_CONFIGURE 的IntenFilter。

需要注意的是,
如果设置了Configure属性,则必须在指定的Activity中进行如下处理:
1.在onCreate中setContentView()函数前添加setResult(RESULT_CANCLE) ,这样如果在Activity初始化完成前按下了BACK按键,则Widget不会启动;
2.在setContentView()函数之后(不一定要在onCreate中,在Activity退出前即可),添加如下设置以指定需要启动的Widget:

  1. int mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
  2. Intent resultValue = new Intent();
  3. resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
  4. setResult(RESULT_OK, resultValue);

否则会导致退出Activity后Widget不启动。
3、AppWidget 框架的主要类介绍
1) AppWidgetManger 类

bindAppWidgetId(int appWidgetId, ComponentName provider) 通过给定的ComponentName 绑定appWidgetId

getAppWidgetIds(ComponentName provider) 通过给定的ComponentName 获取AppWidgetId

getAppWidgetInfo(int appWidgetId) 通过AppWidgetId 获取 AppWidget 信息

getInstalledProviders() 返回一个List的信息

getInstance(Context context) 获取 AppWidgetManger 实例使用的上下文对象

updateAppWidget(int[] appWidgetIds, RemoteViews views) 通过appWidgetId 对传进来的 RemoteView 进行修改,并重新刷新AppWidget 组件

updateAppWidget(ComponentName provider, RemoteViews views) 通过 ComponentName 对传进来的 RemoeteView 进行修改,并重新刷新AppWidget 组件

updateAppWidget(int appWidgetId, RemoteViews views) 通过appWidgetId 对传进来的 RemoteView 进行修改,并重新刷新AppWidget 组件

1、使用bindAppWidgetId缺少权限?

有android.permission.BIND_APPWIDGET权限的apk要放在system/app目录下,

apk的android.permission.BIND_APPWIDGET权限才能起作用。安装在data下是不会起作用的。

发表评论

表情:
评论列表 (有 0 条评论,282人围观)

还没有评论,来说两句吧...

相关阅读