其实Android API开发指南中的App Widgets章节 已经说得很清楚了,下面只是对自己的理解进行一次梳理。
--
AppWidget 就是HomeScreen上显示的小部件,提供直观的交互操作。通过在HomeScreen中长按,在弹出的对话框中选择Widget部件来进行创建,长按部件后并拖动到垃圾箱里进行删除。同一个Widget部件可以同时创建多个。
AppWidget的实现主要涉及到以下类:
AppWidgetProvider
RemoteViews
AppWidgetManager
1.
首先需要提供一个定义了Widget界面布局的XML文件(位于res/layout/..),需要注意的是使用的组件必须是RemoteViews所支持的,目前原生API中支持的组件如下:
FrameLayout
LinearLayout
RelativeLayout
AnalogClock
Button
Chronmeter
ImageButton
ImageView
ProgressBar
TextView
*如果使用了除此之外的组件,则在Widget创建时会导致android.view.InflateExceptionn异常。
PS:这就导致有一些功能或样式无法实现,如很基本的list或文本编辑框都是无法直接实现的。如果想自定义Widget中的View的话只能通过修改framework来提供相应组件的支持。
2.
然后需要提供一个xml文件来定义Widget的基本属性,放置到res/xml/..目录下。
如果使用的是Eclipse可按如下操作:
1) 在res/目录下创建xml/目录
2)创建xml文件(名字可任意),选择类型为AppWidgetProvider
3)在弹出的便捷界面进行参数设置
主要设置的参数如下:
minWidth: 定义Wdiget组件的宽度
minHeight: 定义Wdiget组件的高度
updatePeriodMillis: 更新的时间周期
initialLayout: Widget的布局文件
configure: 如果需要在启动前先启动一个Activity进行设置,在这里给出Activity的完整类名(后面会说到,与一般Activity的实现有些许差别)
*Widget大小的计算 :(单元格数*74)-2,API上说是为了防止像素计算时的整数舍入导致错所以-2...不是很明白
一个完整的样例:
<?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>3.
public class MyWidgetProvider extends AppWidgetProvider { static final String TAG = "widget"; /** * 更新 */ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){ Log.i(TAG, "onUpdate"); } /** * 第一个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); } }
其中onUpdate顾名思义是对Widget进行更新的,前面定义的更新周期就是作用于该函数的。
Widget的更新与Activity不同,必须借助于RemoteViews和AppWidgetMananger。具体实现如下:
public void onUpdate(Context context, AppWidgetMananger appWidgetManager, int[] appWidgetIds){ int N = appWidgetIds.length; // 可能启动了多个Widget,appWidgetIds记录了这些Widget的ID for(int i=0; i<N; i++){ RemoteViews views = new RemoteViews(getPackageName(), R.layout.widget_views); appWidgetManager.updateAppWidget(appWidgetIds[i], views); } }其中需要注意的是,虽然RemoteViews参数都是一样的,但是对于每个Widget最好都新创建一个再进行传递,否则会导致一些错误。具体可参考 AppWidget RemoteViews 内存溢出 。
<receiver android:name="MyWidgetProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"></action> </intent-filter> <meta-data android:resource="@xml/widget_property" android:name="android.appwidget.provider"></meta-data> </receiver>5.
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不启动。
<meta-data android:resource="@xml/<属性文件xml>" android:name="android.appwidget.provider"></meta-data>4. 创建Coniguration Activity(注意处理好setResult),添加到属性文件中的Configure属性,在manifest中注册activity,添加一个 action为 android.appwidget.action.APPWIDGET_CONFIGURE 的IntentFilter