首先来看一个很简单的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/..目录下。
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="80dp" android:minHeight="32dp" android:updatePeriodMillis="86400000" android:initialLayout="@layout/widget_provider" android:configure="com.demo.widget.MyWidgetConfiguration" > </appwidget-provider>
minWidth: 定义Wdiget组件的宽度
minHeight: 定义Wdiget组件的高度
updatePeriodMillis: 更新的时间周期
initialLayout:指定桌面组件的布局文件
configure: 如果需要在启动前先启动一个Activity进行设置,在这里给出Activity的完整类名(后面会说到,与一般Activity的实现有些许差别)
3、接下来就是创建一个继承自AppWidgetProvider的子类,AppWidgetProvider实际上就是一个BroadcastReceiver,里面提供了以下函数:
onReceive(Context, Intent)public class MyAppWidgetProvider extends AppWidgetProvider { private static final String CLICK_NAME_ACTION = "com.terry.action.widget.click"; public static final String TAG = "widget"; public static RemoteViews rv; /** * 更新(Widget的更新与Activity不同,必须借助于RemoteViews和AppWidgetMananger。) */ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){ Log.i(TAG, "onUpdate"); int N = appWidgetIds.length; // 可能启动了多个Widget,appWidgetIds记录了这些Widget的ID for(int i=0; i<N; i++){ int appWidgetId = appWidgetIds[i]; rv = new RemoteViews(context.getPackageName(), R.layout.main); Intent intentClick = new Intent(CLICK_NAME_ACTION); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intentClick, 0); rv.setOnClickPendingIntent(R.id.TextView01, pendingIntent); appWidgetManager.updateAppWidget(appWidgetId, rv); } } /** * 第一个Widget组件启动时触发 */ public void onEnabled(Context context){ Log.i(TAG, "onEnabled"); } /** * 最后一个Widget组件关闭时触发 */ public void onDisabled(Context context){ Log.i(TAG, "onDisabled"); } /** * 任一Widget组件被删除时触发 */ public void onDeleted(Context context, int[] appWidgetIds){ Log.i(TAG, "onDeleted"); } /** * 以上函数触发前会先触发该函数,一般不需要重写 */ public void onReceive(Context context, Intent intent){ Log.i(TAG, "onReceive"); super.onReceive(context, intent); if (rv == null) { rv = new RemoteViews(context.getPackageName(), R.layout.main); } if (intent.getAction().equals(CLICK_NAME_ACTION)) { rv.setTextViewText(R.id.TextView01, context.getResources() .getString(R.string.load)); } AppWidgetManager appWidgetManger = AppWidgetManager.getInstance(context); int[] appIds = appWidgetManger.getAppWidgetIds(new ComponentName(context, widgetProvider.class)); appWidgetManger.updateAppWidget(appIds, rv); } }
其中需要注意的是,虽然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。
<receiver android:name="MyWidgetProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"></action> <action android:name="com.terry.action.widget.click"></action> </intent-filter> <meta-data android:resource="@xml/widget_property" android:name="android.appwidget.provider"></meta-data> </receiver>
int mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); Intent resultValue = new Intent(); resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); setResult(RESULT_OK, resultValue);否则会导致退出Activity后Widget不启动。
bindAppWidgetId(int appWidgetId, ComponentName provider) 通过给定的ComponentName 绑定appWidgetId
getAppWidgetIds(ComponentName provider) 通过给定的ComponentName 获取AppWidgetId
getAppWidgetInfo(int appWidgetId) 通过AppWidgetId 获取 AppWidget 信息
getInstalledProviders() 返回一个List<AppWidgetProviderInfo>的信息
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下是不会起作用的。