android官方文档之路--AppWidget
2016-10-03 15:33
357 查看
App Widgets是小型应用程序视图,可以嵌入在其他应用程序(如主屏幕),并接收定期更新。下面的截图显示音乐应用程序部件。
AppWidgetProviderInfo object:
描述了一种应用程序组件的元数据(相应的配置信息),如应用程序部件的布局,更新频率,和AppWidgetProvider类。这应该在XML中定义。
AppWidgetProvider class implementation:
定义了基本的方法,让你的应用程序编程接口部件,基于广播的事件。通过它,你将收到广播时,应用程序部件更新,启用,禁用和删除。
View layout:
定义应用程序部件的初始布局,在XML中定义。
此外,还可以实现一个应用程序组件配置活动。这是一个可选的活动,当用户添加应用程序小部件,在创建时允许修改应用程序部件设置。
receiver元素需要android:name属性,指定App Widget使用的AppWidgetProvider。
intent-filter元素必须声明一个action元素中的android:name属性,该属性表示AppWidgetProvider会接受一个ACTION_APPWIDGET_UPDATE广播。这是必须声明的广播。AppWidgetManager自动发送所有的其他App Widget 广播给AppWidgetProvider。
meta-data元素指定AppWidgetProviderInfo资源并且需要以下属性。
Android:name 指定metadata名字,使用android.appwidget.provider作为AppWidgetProviderInfo描述符去识别数据。
Android:resource 指定AppWidgetProviderInfo资源位置。
关于
minWidth和minHeight:指定默认的应用程序部件消耗的最小空间。主屏幕窗口是一个网格,网格划分成一个一个定义了高度和宽度的单元格。如果一个应用程序组件的最小宽度或高度的值不匹配的单元格的尺寸,应用程序部件尺寸变成最近的单元格大小。
注意:应用程序部件的最小尺寸不应该大于4×4单元格。
minResizeWidth和minResizeHeight:指定应用程序部件的绝对最小尺寸。使用这些属性允许用户调整窗口大小,可以小于控件定义的minwidth和minheight属性。
UpdatePreiodMillis:定义App Widget框架应该多久调用请求一次更新,去调用AppWidgetProvider中onUpdate()方法。实际的更新不保证在设置的值这个点准确发生,建议尽可能少的更新,一个小时最好不超过一次,以节省电池。你也可以允许用户在配置中调整频率。
注意:当通过updatePeriodMillis定义的更新时间到来时,如果此时设备处于asleep状态时,设备将被唤醒去实现更新。如果更新次数每小时不超过一次,这可能不会对电池寿命造成重大问题。然而如果在设备处于asleep状态时需要频繁更新或者不需要更新时,应该通过一个alarm去实现更新,这将不会唤醒设备。需要使用AlarmManager,并将alarm的类型设置为ELAPSED_REALTIME或RTC。将updatePeriodMillis设置为0。
下面是一个简单的例子:
initialLayout:指向app widget的布局资源。初始化布局。
Configure:定义当用户添加app widget时启动的活动,用于让用户配置应用程序部件属性。
previewImage:一个appwidget的预览图片,用户在选择appwidget时看到。如果没有提供,用户将看到应用程序的启动图标。此字段对应于在AndroidManifest.xml文件中
resizeMode:规定一个部件可以调整的规则。使用这个属性使appwidget可水平,垂直调整大小。用户触摸部件去显示调整大小的句柄,然后拖动水平或垂直手柄,以改变布局网格上的大小。resizeMode属性的值包括“horizontal”,“vertical”,和“none”。声明一个部件的水平和垂直调整大小,提供”horizontal|vertical”。
下图显示当设置为horizontal时,显示出的调整句柄
WidgetCategory:声明你的应用是否控件可以显示在主屏幕(home_screen),锁屏(keyguard),或两者。在Android5.0以上只支持home_screen。
一个RemoteViews对象(一个应用程序组件)可以支持以下布局类:
FrameLayout,LinearLayout,RelativeLayout,GridLayout
和下面的小部件类:
AnalogClock,Button,Chronometer,ImageButton,ImageView
ProgressBar,TextView,ViewFlipper,ListView,GridView
StackView,AdapterViewFlipper
这些类的后代不被支持。
onUpdate():
在AppWidgetProviderInfo中通过updatePeriodMillis属性定义更新间隔时间,根据每隔该时间段调用一次更新。用户添加appwidget,此方法也被调用时,因此,它应该执行必要的设置,如为视图定义事件处理程序,并启动临时服务(如果需要的话)。如果您已经声明了一个Configuration Activity,当用户添加app widget时,onUpdate()方法不会被调用,系统会启动声明的Configuration Activity,但在后续的更新中onUpdate()方法将被调用。当配置完成时,Configur
d79a
ation Activity需要去执行第一次更新。
onAppWidgetOptionsChanged():
当APP Widget首次被放置和任意时刻重调大小时,该方法被调用。可以使用此回调来显示或隐藏基于小部件大小范围的内容。通过调用getAppWidgetOptions()可以得到一个大小范围,返回一个包含以下信息的bundle。
OPTION_APPWIDGET_MIN_WIDTH- 包含当前宽度的下限,单位DP
OPTION_APPWIDGET_MIN_HEIGHT-包含当前高度的下限,单位DP
OPTION_APPWIDGET_MAX_WIDTH-包含当前宽度的上限,单位DP
OPTION_APPWIDGET_MAX_HEIGHT-包含当前高度的上限,单位DP
这个方法在API16中被引进(Android4.1)。如果实现了这个回调,请确保应用程序不依赖它,因为它不会在旧设备上被调用。
onDeleted(Context,int[]):
每次当APP Widget从App Widget host中被删除时调用。
onEnabled(Context):
当一个App Widget首次创建一个实例时被调用。例如,如果用户添加了两个应用程序组件的实例,只在第一次时调用。如果你需要打开一个新的数据库或执行其他设置,所有app widget的实例只需要发生一次情况下,那么这是一个很好的地方用于实现。
onDisabled(Context):
当最后一个AppWidget的实例从AppWidget host中被删除时调用。在该方法中你可以清理在onEnabled(Context)中做的任何工作,如删除临时数据库。
onReceive(Context,Intent)
接受到广播时调用,并且在上述方法之前被调用。通常不需要实现这个方法因为默认的appwidgetprovider实现过滤所有App Widget广播并且适当的调拥上述方法。
上述方法中最重要的是onUpdate()方法,因为当每个App Widget添加进主屏幕中时,该方法会被调用(除非使用了configuration Activity)。如果appwidget接受任何用户交互事件,那么需要在这个回调中注册事件处理程序。如果appwidget不创建临时文件或数据库,或执行其他需要清理的工作,那么onUpdate()可能是唯一需要定义的回调方法。例如,如果希望点击AppWidget中的一个按钮去启动一个Activity,你可以使用下面的AppWidgetProvider实现方式:
注意:代码中对appWidgetIds进行了循环,该数组存放了一组用于识别通过该provider创建的每个App Widget的ID。这样,如果用户创建了一个应用程序部件的一个实例,那么他们都同时更新了。然而,只有updatePeriodMillis schedul才能管理所有的App Widget实例。例如,如果更新计划被定义为每两个小时更新,并且在第一个实例创建一小时后添加第二个实例,那么它们将同时更新根据第一个实例定义的期间,第二个更新区间将被忽略(它们将每两小时同时更新,不是每小时)
同时,活动要在appwidgetproviderinfo XML文件中声明,android:configure
当AppWidget创建时,onUpdate()方法不被调用(当一个configuration activity启动时系统不会发送ACTION_APPWIDGET_UPDATE广播)。当AppWidget第一次创建时,configuration Activity有义务向AppWidgetManager请求一次更新。然而,onUpdate()将会在之后的更新中被调用-只是单单跳过第一次。
1.从启动Activity的Intent中获取AppWidgetID
2.执行appWidget 配置。
3.当配置完成,通过调用getInstance(Context)获取一个AppWidgetManager实例。
4.通过调用updateAppWidget(int ,RemoteViews)根据RemoteViews来更新AppWidget。
5.创建一个返回的Intent,设置活动结果,并结束活动:
1.创建一个AppWidgetProvider
一个布局文件
2.在res/xml中创建一个AppWidgetProviderInfo meta-data文件
3.在AndroidManifest.xml中声明
完成以上三步,一个简单的appwidget就完成了,具体的例子可以看appWidget小应用—-简易音乐播放器
The Basics
创建一个App Widget,需要实现以下几个方面:AppWidgetProviderInfo object:
描述了一种应用程序组件的元数据(相应的配置信息),如应用程序部件的布局,更新频率,和AppWidgetProvider类。这应该在XML中定义。
AppWidgetProvider class implementation:
定义了基本的方法,让你的应用程序编程接口部件,基于广播的事件。通过它,你将收到广播时,应用程序部件更新,启用,禁用和删除。
View layout:
定义应用程序部件的初始布局,在XML中定义。
此外,还可以实现一个应用程序组件配置活动。这是一个可选的活动,当用户添加应用程序小部件,在创建时允许修改应用程序部件设置。
Declaring an App Widget in the Manifest
首先,在AndroidManifest.xml文件中声明AppWidgetProvider类(AppWidgetProvider类继承自BroadcastReceiver)。例如:<receiver android:name=".ExampleAppWidgetProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/example_appwidget_info" /> </receiver>
receiver元素需要android:name属性,指定App Widget使用的AppWidgetProvider。
intent-filter元素必须声明一个action元素中的android:name属性,该属性表示AppWidgetProvider会接受一个ACTION_APPWIDGET_UPDATE广播。这是必须声明的广播。AppWidgetManager自动发送所有的其他App Widget 广播给AppWidgetProvider。
meta-data元素指定AppWidgetProviderInfo资源并且需要以下属性。
Android:name 指定metadata名字,使用android.appwidget.provider作为AppWidgetProviderInfo描述符去识别数据。
Android:resource 指定AppWidgetProviderInfo资源位置。
Adding the AppWidgetProviderInfo Metadata
AppWidgetProviderInfo定义一个应用程序窗口小部件的基本特点,如它的最小布局尺寸,它的初始布局资源,如何经常更新应用程序部件,以及在创建时启动一个配置活动(可选)。在xml资源文件中使用一个单一的appwidget-provider元素去定义AppWidgetProviderInfo对象,将该xml文件保存在res/xml文件下。<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="40dp" android:minHeight="40dp" android:updatePeriodMillis="86400000" android:previewImage="@mipmap/ic_launcher" android:initialLayout="@layout/appwidget_provider_layout" android:configure="ce.com.appwidgettext.ExampleAppWidgetConfigure" android:resizeMode="horizontal" android:widgetCategory="home_screen"> </appwidget-provider>
关于
<appwidget-provider>属性:
minWidth和minHeight:指定默认的应用程序部件消耗的最小空间。主屏幕窗口是一个网格,网格划分成一个一个定义了高度和宽度的单元格。如果一个应用程序组件的最小宽度或高度的值不匹配的单元格的尺寸,应用程序部件尺寸变成最近的单元格大小。
注意:应用程序部件的最小尺寸不应该大于4×4单元格。
minResizeWidth和minResizeHeight:指定应用程序部件的绝对最小尺寸。使用这些属性允许用户调整窗口大小,可以小于控件定义的minwidth和minheight属性。
UpdatePreiodMillis:定义App Widget框架应该多久调用请求一次更新,去调用AppWidgetProvider中onUpdate()方法。实际的更新不保证在设置的值这个点准确发生,建议尽可能少的更新,一个小时最好不超过一次,以节省电池。你也可以允许用户在配置中调整频率。
注意:当通过updatePeriodMillis定义的更新时间到来时,如果此时设备处于asleep状态时,设备将被唤醒去实现更新。如果更新次数每小时不超过一次,这可能不会对电池寿命造成重大问题。然而如果在设备处于asleep状态时需要频繁更新或者不需要更新时,应该通过一个alarm去实现更新,这将不会唤醒设备。需要使用AlarmManager,并将alarm的类型设置为ELAPSED_REALTIME或RTC。将updatePeriodMillis设置为0。
下面是一个简单的例子:
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); int appWidgetId=appWidgetIds[i]; //启动一个Activity Intent intent=new Intent(context,MainActivity.class); PendingIntent pendingIntent=PendingIntent.getActivity(context,0,intent,0); AlarmManager alarm = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); //实现“提醒”功能,第二个参数表示首次提醒的时间,第三个参数表示多久重复,第四个参数表示执行的动作, //开启一个Activity alarm.setRepeating(AlarmManager.RTC,System.currentTimeMillis()+10*1000, 60 * 1000, pendingIntent); appWidgetManager.updateAppWidget(appWidgetId,remoteViews); }
initialLayout:指向app widget的布局资源。初始化布局。
Configure:定义当用户添加app widget时启动的活动,用于让用户配置应用程序部件属性。
previewImage:一个appwidget的预览图片,用户在选择appwidget时看到。如果没有提供,用户将看到应用程序的启动图标。此字段对应于在AndroidManifest.xml文件中
<receiver>元素中android:previewImage属性。
resizeMode:规定一个部件可以调整的规则。使用这个属性使appwidget可水平,垂直调整大小。用户触摸部件去显示调整大小的句柄,然后拖动水平或垂直手柄,以改变布局网格上的大小。resizeMode属性的值包括“horizontal”,“vertical”,和“none”。声明一个部件的水平和垂直调整大小,提供”horizontal|vertical”。
下图显示当设置为horizontal时,显示出的调整句柄
WidgetCategory:声明你的应用是否控件可以显示在主屏幕(home_screen),锁屏(keyguard),或两者。在Android5.0以上只支持home_screen。
Creating the App Widget Layout
与activity类似,app widget也需要在XML中定义一个初始布局。创建布局是简单,但appwidget的布局是基于RemoteViews,不支持所有的布局或视图控件。一个RemoteViews对象(一个应用程序组件)可以支持以下布局类:
FrameLayout,LinearLayout,RelativeLayout,GridLayout
和下面的小部件类:
AnalogClock,Button,Chronometer,ImageButton,ImageView
ProgressBar,TextView,ViewFlipper,ListView,GridView
StackView,AdapterViewFlipper
这些类的后代不被支持。
Using the AppWidgetProvider Class
AppWidgetProvider类继承自BroadcastReceiver,作为一个方便的类来处理应用程序组件的广播。AppWidgetProvider只接收与App Widget相关的广播,如当应用程序部件被更新,删除,启用和禁用。当这些事件发生时的广播,AppWidgetProvider接收广播并调用以下方法:onUpdate():
在AppWidgetProviderInfo中通过updatePeriodMillis属性定义更新间隔时间,根据每隔该时间段调用一次更新。用户添加appwidget,此方法也被调用时,因此,它应该执行必要的设置,如为视图定义事件处理程序,并启动临时服务(如果需要的话)。如果您已经声明了一个Configuration Activity,当用户添加app widget时,onUpdate()方法不会被调用,系统会启动声明的Configuration Activity,但在后续的更新中onUpdate()方法将被调用。当配置完成时,Configur
d79a
ation Activity需要去执行第一次更新。
onAppWidgetOptionsChanged():
当APP Widget首次被放置和任意时刻重调大小时,该方法被调用。可以使用此回调来显示或隐藏基于小部件大小范围的内容。通过调用getAppWidgetOptions()可以得到一个大小范围,返回一个包含以下信息的bundle。
OPTION_APPWIDGET_MIN_WIDTH- 包含当前宽度的下限,单位DP
OPTION_APPWIDGET_MIN_HEIGHT-包含当前高度的下限,单位DP
OPTION_APPWIDGET_MAX_WIDTH-包含当前宽度的上限,单位DP
OPTION_APPWIDGET_MAX_HEIGHT-包含当前高度的上限,单位DP
这个方法在API16中被引进(Android4.1)。如果实现了这个回调,请确保应用程序不依赖它,因为它不会在旧设备上被调用。
onDeleted(Context,int[]):
每次当APP Widget从App Widget host中被删除时调用。
onEnabled(Context):
当一个App Widget首次创建一个实例时被调用。例如,如果用户添加了两个应用程序组件的实例,只在第一次时调用。如果你需要打开一个新的数据库或执行其他设置,所有app widget的实例只需要发生一次情况下,那么这是一个很好的地方用于实现。
onDisabled(Context):
当最后一个AppWidget的实例从AppWidget host中被删除时调用。在该方法中你可以清理在onEnabled(Context)中做的任何工作,如删除临时数据库。
onReceive(Context,Intent)
接受到广播时调用,并且在上述方法之前被调用。通常不需要实现这个方法因为默认的appwidgetprovider实现过滤所有App Widget广播并且适当的调拥上述方法。
上述方法中最重要的是onUpdate()方法,因为当每个App Widget添加进主屏幕中时,该方法会被调用(除非使用了configuration Activity)。如果appwidget接受任何用户交互事件,那么需要在这个回调中注册事件处理程序。如果appwidget不创建临时文件或数据库,或执行其他需要清理的工作,那么onUpdate()可能是唯一需要定义的回调方法。例如,如果希望点击AppWidget中的一个按钮去启动一个Activity,你可以使用下面的AppWidgetProvider实现方式:
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { int N=appWidgetIds.length; for (int i=0;i<N;i++) { int appWidgetId=appWidgetIds[i]; Intent intent=new Intent(context,MainActivity.class); PendingIntent pendingIntent=PendingIntent.getActivity(context,0,intent,0); RemoteViews remoteViews=new RemoteViews(context.getPackageName(),R.layout.appwidget_provider_layout); //添加点击事件,点击启动Activity remoteViews.setOnClickPendingIntent(R.id.button,pendingIntent); appWidgetManager.updateAppWidget(appWidgetId,remoteViews); } }
注意:代码中对appWidgetIds进行了循环,该数组存放了一组用于识别通过该provider创建的每个App Widget的ID。这样,如果用户创建了一个应用程序部件的一个实例,那么他们都同时更新了。然而,只有updatePeriodMillis schedul才能管理所有的App Widget实例。例如,如果更新计划被定义为每两个小时更新,并且在第一个实例创建一小时后添加第二个实例,那么它们将同时更新根据第一个实例定义的期间,第二个更新区间将被忽略(它们将每两小时同时更新,不是每小时)
Creating an App Widget Configuration Activity
当用户添加一个新的appwidget时,希望用户对该appwidget进行一些配置,可以创建一个AppWidget Configuration Activity。该Activity允许用户在创建appwidget时对其进行设置,如该appwidget的颜色,大小,更新时间或其他功能设置。Configuration Activity需要在AndroidManifest中被声明。App Widget host根据ACTION_APPWIDGET_CONFIGURE action启动。activity android:name=".ExampleAppWidgetConfigure"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/> </intent-filter> </activity>
同时,活动要在appwidgetproviderinfo XML文件中声明,android:configure
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" ... android:configure="ce.com.appwidgettext.ExampleAppWidgetConfigure" ... </appwidget-provider>
当AppWidget创建时,onUpdate()方法不被调用(当一个configuration activity启动时系统不会发送ACTION_APPWIDGET_UPDATE广播)。当AppWidget第一次创建时,configuration Activity有义务向AppWidgetManager请求一次更新。然而,onUpdate()将会在之后的更新中被调用-只是单单跳过第一次。
Updating the App Widget from the configuration Activity
当AppWidget使用一个configuration Activity时,该Activity需要去更新AppWidget当配置完成时。1.从启动Activity的Intent中获取AppWidgetID
private int mAppWidgetId= AppWidgetManager.INVALID_APPWIDGET_ID;
Intent intent=getIntent(); Bundle extras=intent.getExtras(); if(extras!=null) { mAppWidgetId=extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); } if (mAppWidgetId==AppWidgetManager.INVALID_APPWIDGET_ID) { finish(); }
2.执行appWidget 配置。
3.当配置完成,通过调用getInstance(Context)获取一个AppWidgetManager实例。
AppWidgetManager mAppWidgetManager=AppWidgetManager.getInstance(this);
4.通过调用updateAppWidget(int ,RemoteViews)根据RemoteViews来更新AppWidget。
ppWidgetManager mAppWidgetManager=AppWidgetManager.getInstance(this); RemoteViews views=new RemoteViews(this.getPackageName(),R.layout.appwidget_provider_layout); mAppWidgetManager.updateAppWidget(mAppWidgetId,views);
5.创建一个返回的Intent,设置活动结果,并结束活动:
Intent resultValue=new Intent(); resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,mAppWidgetId); setResult(RESULT_OK,resultValue); finish();
总结
创建一个简单的appwidget基本上需要三步1.创建一个AppWidgetProvider
public class ExampleAppWidgetProvider extends AppWidgetProvider{ @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { int N=appWidgetIds.length; for (int i=0;i<N;i++) { int appWidgetId=appWidgetIds[i]; Intent intent=new Intent(context,MainActivity.class); PendingIntent pendingIntent=PendingIntent.getActivity(context,0,intent,0); RemoteViews remoteViews=new RemoteViews(context.getPackageName(),R.layout.appwidget_provider_layout); remoteViews.setOnClickPendingIntent(R.id.button,pendingIntent); appWidgetManager.updateAppWidget(appWidgetId,remoteViews); } } }
一个布局文件
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:padding="@dimen/widget_margin" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout> </FrameLayout>
2.在res/xml中创建一个AppWidgetProviderInfo meta-data文件
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="40dp" android:minHeight="40dp" android:updatePeriodMillis="86400000" android:previewImage="@mipmap/ic_launcher" android:initialLayout="@layout/appwidget_provider_layout" android:resizeMode="horizontal|vertical" android:widgetCategory="home_screen"> </appwidget-provider>
3.在AndroidManifest.xml中声明
<receiver android:name=".ExampleAppWidgetProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/example_appwidget_info" /> </receiver>
完成以上三步,一个简单的appwidget就完成了,具体的例子可以看appWidget小应用—-简易音乐播放器
相关文章推荐
- Android---App Widget(官方文档翻译)
- Android: AppWidget开发官方文档
- Android Web App官方文档翻译第一章:概览
- Android Web App官方文档翻译第五章:最佳实践
- Android官方文档之App Resources(中)
- android官方文档之路--Wi-Fi Peer-to-Peer
- Android官方开发文档Training系列课程中文版:APP的内存管理
- Android Web App官方文档翻译第四章:调试
- Android官方开发文档Training系列课程中文版:分享简单数据之从其它APP接收简单数据
- Android官方文档之App Resources(下)
- Android官方开发文档Training系列课程中文版:管理音频播放之控制APP的音量与播放
- Android官方开发文档Training系列课程中文版:APP的内存管理
- Android官方开发文档Training系列课程中文版:与其它APP交互之允许其它APP启动你的Activity
- Android官方文档翻译 二 1.Building Your First App
- Android Studio官方文档之添加URL和App索引支持
- Android Web App官方文档翻译第三章:WebView构建应用
- 【android官方文档】与其他App交互
- Android官方开发文档Training系列课程中文版:与其它APP交互之将用户带到其它的APP
- Android官方开发文档Training系列课程中文版:与其它APP交互之从Activity获得结果
- android官方文档之路--activity生命周期