android widget的中文文档

下文是我翻译于 App Widgets的文章,如果有不当之处请大家指出


app widget是一种嵌入在其他应用(例如主屏幕)和并且能偶接受间接性更新的小应用,你可以自己提供app widget provider 来在用于界面上定义app widget,包含了app  widget的应用程序组件叫做app widget host.


1.基础的工作

AppWidgetProviderInfo 对象

描述了app widget 所需的元数据,例如app widget 的布局,更新的频率 和实现AppWidgetProvider的类,这些都应该定义的XML文件夹中。


继承实现AppWidgetProvider对象

     定义了一些基本的方法,这些方法能够让你与app widget进行交互,这些方法都是基于android的广播事件,当你的app widget调用updated(),enabled(),disabled()和delete()的方法的时候都会接收到广播。


2.在AndroidManifest.xml文件中进行相应的配置

    首先需要在AndroidManifest.xml中声明你自己实现的AppWidgetProvider类,如下

 

<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这个属性,这个标签指定了你自己继承实现AppWigetProvider的类,同时你还要在<intent-fliter>这个标签中指定一个包含android:name的标签,这个标签表示将会去过滤会包含了ACTION_APPWIDGT_UPDATE的广播,这是唯一一个是你必须要明确指定接受的广播,系统的AppWidgetManager将会自动的将app widget广播发送到需要接受的AppWidgetProvider的实现类中。

 

<meta-data>元素指定了AppWidgetProviderInfo的信息并且必须包含下面两个信息。

android:name:这个属性指定了元数据的名称。使用android.appwidget.provider来指定数据作为AppWidgetProviderInfo的描述信息。

anndroid:resources 来指定AppWidgetProviderInfo描述信息的位置。


3.添加AppWidgetProviderInfo的元数据

AppWidgetProviderInfo定义了App Widget的基本信息,例如布局尺寸的最小值,和初始化布局文件的资源,更新app widget的频率,同时你还可以定义在创建widget的时候启动一个activity,这一项是可选的。你需要在res下新建一个xml目录,在这个目录中创建一个xml文件,这个xml文件的根元素必须要是<appwidget-provider>,例如下面的例子。

 

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="294dp"
    android:minHeight="72dp"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/example_appwidget"
    android:configure="com.example.android.ExampleAppWidgetConfigure" >
</appwidget-provider>

    下面是对xml文件中元素的说明

 

      minWidth和minHeight属性指定了app widget布局文件所需要最小尺寸。

      在主屏幕上放置的app widget取决于定义了宽和高的网格,如果我们自定义的最小宽或者高不和屏幕网格中的格子不匹配,那么app widget的尺寸会自动的变成与当前格子最匹配的尺寸,因为屏幕的方向是可以改变的,因此网格格子尺寸大小也是可以变化的,所以建议你假设格子的宽和高的值为74像素,同时,你应该从最终的尺寸计算中减去2,因为可能会出现的像素计算问题。为了计算出最佳的宽和高,建议你使用下面的公式。

(number of cells * 74) - 2

因此,可以使用72来作为一个app widget的高,使用294来作为一个app widget的宽,宽度包含了四个格子。

         updatePeriodMillis属性定义了app widget要求调用AppWidgetProvider 实现类的onUpdate方法的频率。但是并不能保证能够在准确的时间去调用这个更新方法,我们建议这个更新的周期越大越好,从省电的角度来看,一个小时不要超过一次。你也应该允许用户去配置这个调用的周期,例如有人需要每一刻钟去更新证券的信息,有的人可能一天只更新四次。注意:如果到了更新的时候,设备正处于休眠期,那么设备将会被唤醒去完成这次更新。如果你一个小时以内更新的频率低于一次,那么这将不会对你的电池造成什么明显的影响,如果你更新的十分频繁,或者不需要在设备休眠的时候更新,那么建议你使用闹钟来完成这个功能,在闹钟中你可以设定是否需要唤醒设备。你可以设定闹钟的类型为ELAPSED_REALTIME或者RTC,这将只在设备处于唤醒状态进行更新。那么在这种情况下,你可以设定updatePeriodMillis为0

initiaLayou属性指定了app widget的布局文件。

configure属性指定了当用户创建一个app widget的时候需要启动的activity,这个属性允许用户去设定app widget的属性.。这一项是可选的。


4.创建App Widget的布局文件

必须定义一个在res/layout中定义一个布局文件,来作为app widget的初始化布局文件。你可以使用下面列表中出现的View对象来作为布局文件。

如果你属性创建布局文件,那么创建一个app widget的布局文件同样是一个很简单的事情,但是需要注意的事情是app widget的布局是基于RemoteViews的,这些并不是支持所有的布局文件,只有下面三种是被支持的:FrameLayout,LinearLayout和RelativeLayout,同时下面这七种Widget对象也是被支持的:AnalogClock,Button,Chronometer,ImageButton,ImageView,ProgressBar和TextView。



5.使用AppWidgetProvider class

      AppWidgetProvider 类继承了BroadcastReceiver,这样方便于去处理App Widget广播,AppWidgetProvider类只处理与App Widget相关的广播,例如当app widget 发生以下的事件updated,deleted,endabled和disabled。当这些广播事件发生以后,AppWidgetProvider会调用这些方法

     onUpdate(Context context,AppWidgetManager,int [] widgetids) 这个方法会在updatePeriodMillis属性定义的时间周期类调用,当用户添加新的App Widget的时候,这个方法也会被调用。因此在这个方法里面需要执行一些必要的设置,例如设定一个视图的事件处理器或者启动一个临时的服务。但是,如果你为app widget添加了启动的activity,那么在用户添加app widget的时候,这个方法不会被执行,但是在随后的更新中,这个方法会被执行。在完成配置任务的activity完成配置的时候要执行一次更新。

     onDeleted(Context context,int [] widgetsid)每当App Widget被删除的时候调用

     onEnabled(Context context)这个方法只会在第一次创建app widget的时候被调用,例如,当用户创建了两个app widget,这个方法只会在创建第一个app widget的时候被调用,如果你需要使用数据库或者其他只需要只执行一次的设定,那么你可以将它们放在这个方法里面调用。当最后一个app widget实例被删除的时候,这个方法会被调用。在这里你可以完成一些必要的清理工作。

      onReceive(Context context,Intent intent)这个方法在收到关于app widget的广播之后并且在上面所有的方法调用之前被调用,实际上你并不需要自己去实现这个方法,因为在AppWidgetProvider提供的默认实现中,会根据系统的广播来在上面的方法选择一个调用。

在AppWidgetProvider所有的方法中最重要的是Onupdate方法,因为每次添加一个app widget的都会被调用,除非你为你的app widget配置了一个activity.如果你的app widget需要处理与用户的交互事件,那么你也许需要在这个方法中定义一个事件处理的handler,如果你的app widget不需要创建临时性的文件或者其他需要在最后处理的任务,那么你或许仅仅需要在onupdate中来定义自己业务处理逻辑,其他的方法空实现即可。例如,当你的app widget中包含一个button,当点击button的时候,需要启动一个activity,那么下面的示例可以供你参考。

 

public class ExampleAppWidgetProvider extends AppWidgetProvider {

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        final int N = appWidgetIds.length;

        // Perform this loop procedure for each App Widget that belongs to this provider
        for (int i=0; i<N; i++) {
            int appWidgetId = appWidgetIds[i];

            // Create an Intent to launch ExampleActivity
            Intent intent = new Intent(context, ExampleActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

            // Get the layout for the App Widget and attach an on-click listener to the button
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
            views.setOnClickPendingIntent(R.id.button, pendingIntent);

            // Tell the AppWidgetManager to perform an update on the current App Widget
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }
}

这个AppWidgetProvider实现类仅仅定义了onupdate方法,在这个方法中我们定义了一个可以启动activity的PendingIntent,我们点击了注册了setOnClickPendingIntent()方法的button时,会启动我们定义的activity.需要注意的是,在这个方法里面包含了对appwidgetids数组的遍历,这个数组是当我们创建app widget的时候AppWidgetProvider为我们创建的。 此外,当用户创建了不止一个app widget的时候,这些app widget会全部同时的更新。但是针对更新的频率我们只能定义一个updatePeriodMillis属性。例如当我们设定更新周期为两个小时一次,我们创建两个app widget之间相隔了一个小时,那么第二个被添加的app widget也会在第一个app widget 被添加两个小时之后更新。第二个的更新周期会被忽略。

 

       注意:因为AppWidgetProvider是继承与BroadcastReceiver,你的进程在这些方法返回之后并不能保证会继续执行,如果你的进程需要进行耗时的操作,那么请考虑一下在onupdate方法中启动一个service,在这个service中,你可以考虑继续进行你需要完成的工作而不需要担心ANR


6.接收到的App Widget 广播意图

AppWidgetProvider是一个方便用来处理接收到的AppWidget 广播的类。如果你需要直接接受到App Widget的广播,那么你可以实现你自己的BroadcastReceiver或者重写onReceiver方法。下面这四种意图是你需要关心的。

ACTION_APPWIDGET_UPDATE   ACTION_APPWIDGET_DELETED ACTION_APPWIDGET_ENABLED  ACTION_APPWIDGET_DISABLED


7.为app widget 添加启动的activity

如果你想在用户创建一个app widget的时候可以配置app widget的基本信息,你可以为app widget配置一个activity,用户可以通过这个activity来配置widget 的更新频率,大小,颜色或者其他功能性的设置。

这个配置性的Activity同样需要在AndroidManifest.xml文件中进行声明,但是这个activity需要对android.appwidget.action.APPWIDGET_CONFIGURE 进行过滤。如下面的示例

 

<activity android:name=".ExampleAppWidgetConfigure">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
    </intent-filter>
</activity>

 

同样需要在AppWidgetProviderInfo xml文件中定义这个activity的信息。示例如下:

 

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:configure="com.example.android.ExampleAppWidgetConfigure" 
    ... >
</appwidget-provider>

类的名称一定是全限定名称,因为你可能引用了其他包的类。这些就是启动activity所需要的。现在你需要的就是一个继承了Activity的类,但是你还需要注意下面两点。

 

①这个activity需要返回一个结果,这个结果中包含了intent传递过来的App Widget ID

        ②当app widget被创建的时候 onupdate方法不会被执行,因为在启动activity的时候,系统不会发出 ACTION_APPWIDGET_UPDATE广播,那么当加载activity之后,activity需要主动去要求一次更新app widget。否则出了第一次会被跳过意外,后面的更新会被执行。

下面给出了配置activity实现。


8.通过activity更新app widget

    如果创建app widget的时候使用了activity,那么在activity配置结束的时候应该主动要求更新一次app widget。可以通过AppWidgetManager来完成一次更新的请求。

下面是要求更新app widget的步骤。

①首先通过启动Activity的intent 获取App Widget id

 

Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
    mAppWidgetId = extras.getInt(
            AppWidgetManager.EXTRA_APPWIDGET_ID, 
            AppWidgetManager.INVALID_APPWIDGET_ID);
}

②完成用户配置的设置。

 

③当配置完成以后,通过调用AppWidgetManager的getIntance(Context context)来得到AppWidgetManager的实例。

 

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

 

④通过RemoteViews并且调用AppWidgetManager实例的updateAppWidget方法来完成更新。

 

RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
appWidgetManager.updateAppWidget(mAppWidgetId, views);

⑤最后创建一个返回的Intent

 

 

Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();

 


上面的翻译来自于个人的理解,部分语言实在是不知道怎么翻译,希望大家多多指点。
























 

posted on 2013-12-19 09:52  我的小人生  阅读(342)  评论(0编辑  收藏  举报