android之widget详解
首先来看一个很简单的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)
onUpdate(Context , AppWidgetManager, int[] appWidgetIds)
onEnabled(Context)
onDeleted(Context, int[] appWidgetIds)
onDisabled(Context)
可通过重写以上函数来监听Widget状态的变化并进行相应的处理。
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>
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:
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不启动。
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下是不会起作用的。
还没有评论,来说两句吧...