开发APP Widget的步骤java
一、继承AppWidgetProvider类,android
public class MyWidget extends AppWidgetProvider{ <!-- 每个Widget放置到桌面上时调用,每一次updatePeriodMillis时间到了以后也会被调用--> public void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) <!-- 移除widget时调用--> public void onDeleted(Context context, int[] appWidgetIds) <!-- 无论添加多少个widget,都只会调用一次 --> public void onEnabled(Context context) <!-- 当最后一个widget从桌面删除的时候调用--> public void onDisabled(Context context) <!-- 可用作Widget上的按键响应处理--> public void onReceive(Context context, Intent intent) }
通常在onUpdate中进行widget中按键的事件处理,和初始化值。app
二、AppWidgetProvider是一个Broadcast,须要在Mainfest.xml中注册。ide
<receiver android:name="继承AppWidgetProvider的类"> <intent-filter > <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_config"/> </receiver
三、 <meta-data>中的android:resource引用的是Widget的配置文件,须要在res/xml下新建,若是xml目录不存在,也须要新建。
布局
widget_config文件
测试
<?xml version="1.0" encoding="UTF-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="40dp" <!-- 显示在桌面上最小的的宽,高,不能大于4*4的格子--> android:minHeight="20dp" android:updatePeriodMillis="1000000" <!-- widget的更新间隔时间--> android:previewImage="@drawable/l7" <!-- 预览图--> android:initialLayout="@layout/my_widgets_layout" <!-- 在桌面的显示布局,在3.0版本以后可使用,默认以应用图标显示。--> android:resizeMode="horizontal|vertical" <!-- 在桌面可调整的方向--> android:configure="cn.fly.widgets.MyWidgetsConfigActivity"> <!-- 当widget在拖到桌面上时,显示的配置文件--> <!--加上如下配置,在4.2版本能够放到锁屏界面上,4.2如下的版本默认是放主屏幕 android:widgetCategory ="home_screen|keyguard" android:initialKeyguardLayout="" 在锁屏界面上显示的布局 --> </appwidget-provider>
设置了updatePeriodMillis后,就算手机处于待机状态,也会唤醒手机去执行更新操做,若是widget更新频繁,这会对手机电池寿命形成影响,因此针对这种状况,可使用AlarmManager来执行定时更新操做,将AlarmManager的Type设置为 ELAPSED_REALTIME 或者 RTC,就能够保证手机在唤醒的状态下执行更新,updatePeriodMillis则须要设置为0。this
在桌面显示的布局文件的跟节点必须是经常使用布局例如:Framelayout,linearLayout,viewStub等,不能使用自定义布局。调试
在4.0之后的版本,widget放置到桌面上是能够根据其余的widget或者快捷图标来扩充边距,使添加的widget可以在桌面视觉上达到协调,可是4.0如下的版本须要本身来设置Padding,使widget能和其余桌面图标达到视觉协调。component
作完以上的操做,一个简单的widget的就完成了,根据应用需求咱们会遇到如下的一些状况。xml
1、相应widget的按键事件
由于widget不是运行在自身的应用的进程中,因此是经过如下方式来处理事件。
RemoteView 进行布局引用。
PendingIntent 进行事件分发。
//这段代码通常写在onUpdate中,所处理的事情是按button更改Textview的显示 final int N = appWidgetIds.length; for(int i = 0;i< N;i++){ Intent intent = new Intent("自定义action用来标示这个intent"); intent.setClass(context, MyWidgets.class); //发送广播,在onReceive()中进行处理PendingIntent也能够启动Activity,也能够//启动Service PendingIntent mPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), "widget布局引用"); //button按键处理 remoteViews.setOnClickPendingIntent(R.id.btn_click, mPendingIntent); appWidgetManager.updateAppWidget(appWidgetIds[i], remoteViews); }
在onReceive()的处理
String action = intent.getAction(); if(action.equals("比较发送的action")){ RemoteViews remoteViews = new RemoteViews(context.getPackageName(),"widget布局引用"); //更改文本显示 remoteViews.setTextViewText(R.id.tv, "测试"); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); ComponentName componentName = new ComponentName(context,MyWidgets.class); appWidgetManager.updateAppWidget(componentName, remoteViews); }
2、widget添加上桌面上时的配置页面
这个配置页面是一个activity,因此须要在mainfest.xml中进行配置
一、在启动这个配置页面的时候,须要在oncreate()方法里面写上setResult(RESULT_CANCELED);这样作是为了防止配置页面尚未显示出来,用户就按了返回键,
setResult(RESULT_CANCELED); super.onCreate(savedInstanceState);
二、须要获取widgetId
Intent intent = getIntent(); Bundle extra = intent.getExtras(); if(extra !=null){ mAppWidgetId = extra.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); }
若是mAppWidgetId为INVALID_APPWIDGET_ID则退出页面显示。
三、当配置页面显示后,用户作完了配置退出页面时,须要将这些配置信息更新到桌面的widget,照着官方给出的文档上来操做的话,只能显示widget可是配置并无生效,参考了appdemo中的例子和我的调试后总结以下。
在MyWidget中写一个静态方法
//describe是一个在配置文件中自由输入文本,而后在widget的text上显示,widget是为了作到代码重用,这里只是一个简单的更改文本,若是涉及到图片更改,列表数据改动等,这些改动若是有配置界面的话基本上和onupdate所作的操做同样。 public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,int appWidgetId, String describe) { RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider); views.setTextViewText(R.id.tv, describe); appWidgetManager.updateAppWidget(appWidgetId, views); }
在配置界面的退出方法中这样写
private void exits(){ String describe = et.getText().toString(); Context context = this; AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); //appWidgetId在进入配置界面的时候已经获取了 MyWidget.updateAppWidget(context,appWidgetManager,appWidgetId , describe ); //配置完成退出界面 Intent intent = new Intent(); resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); setResult(RESULT_OK, intent ); finish(); }
当时参考文档作时,文档中并无提到调用updateAppWidget方法后,退出界面须要从新获取view,并改变view的显示数据。因此我只写了appWidgetManager.updateAppWidget(appWidgetId, views)方法。