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<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下是不会起作用的。





你可能感兴趣的:(android,widget)