Android App Widget设计

App Widget也是一种UI组件,它可以让一小块程序(program piece)嵌入到桌面上。与普通的Widget(TextView、WebView等)相比,有以下几个不同:

  1. App Widget是有生命的UI组件,它会自动更新自身内容;
  2. Widget不能自动更新自身内容,只能被动的等待用户的调用;

应用上,由于App Widget自动更新的特性,所以它比较适合用来设计一些天气,新闻,日历等功能。

App Widget的设计流程:

  1. 规划App Widget的大小及更新时间,在/res/xml目录新增一份XML文件;
  2. 规划App Widget的UI,修改res/layout/main.xml;
  3. 编写App Widget的主程序;
  4. 编辑AndroidManifest.xml,设定App Widget可接受App Widget的更新事件:android.appwidget.action.APPWIDGET_UPDATE

及设计一个App Widget至少需要以下4个文件:

  • res/xml/appwidget_provider.xml
  • res/layout/main.xml
  • src//HelloAppWidgetProvider.java
  • AndroidManifest.xml

下面是一个具体实现App Widget的例子:

新建一个Android工程HelloAppWidget,在/res目录新建一个文件夹xml,在/res/xml目录下新建一个appwidget_provider.xml文件:

[html] view plain copy
  1. xml version="1.0" encoding="utf-8"?>  
  2.      
  3. <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:minWidth="85dp"  
  5.     android:minHeight="30dp"  
  6.     android:updatePeriodMillis="1000"  
  7.     android:initialLayout="@layout/main"  
  8.     >  
  9. appwidget-provider>  
说明如下:
  1. 标签定义App Widget的属性
  2. android:minWidth  宽度
  3. android:minHeight    长度
  4. android:updatePeriodMillis定义App Widget的更新频率,Android框架每隔一段时间,会callback AppWidgetProvider类的onUpdate()事件;以前android的版本设定为1毫秒为单位,现在版本为了省电,更新时间为30~60分钟,所以现在设定30分钟以内的更新意义不大,系统默认为30~60分钟更新
  5. android:initialLayout属性指定此App Widget的UI layout定义,”@”符号在Android的XML定义档案,代表「目录」之意,因此”@layout/main”表示「layout目录下的main.xml档案」
为了界面美观,google提供了App Widget的外观设计原则,以下是官方提供的设计参考:


编辑main.xml文件:
[html] view plain copy
  1. xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.     <TextView  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:text="@string/hello" />  
  11.     <TextView    
  12.     android:layout_width="wrap_content"   
  13.     android:layout_height="wrap_content"   
  14.     android:id="@+id/appwidget_text"  
  15.     android:textColor="#ff0000"  
  16.     />  
  17.       
  18.   
  19. LinearLayout>  
我们的App Widget使用LinearLayout來安排布局,而UI为一个TextView物件。在这里,将此TextView的id定义为”appwidget_text”。

在Android工程中添加一个新类HelloAppWidgetProvider extends AppWidgetProvider:

[java] view plain copy
  1. package com.android;  
  2.   
  3. import java.util.Date;  
  4.   
  5. import android.appwidget.AppWidgetManager;  
  6. import android.appwidget.AppWidgetProvider;  
  7. import android.content.Context;  
  8. import android.widget.RemoteViews;  
  9.   
  10. public class HelloAppWidgetProvider extends AppWidgetProvider {  
  11.     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {  
  12.         final int N = appWidgetIds.length;  
  13.         for (int i=0; i
  14.             int appWidgetId = appWidgetIds[i];  
  15.             updateAppWidget(context, appWidgetManager, appWidgetId);  
  16.         }  
  17.     }  
  18.         
  19.     public void onDeleted(Context context, int[] appWidgetIds) {  
  20.     }  
  21.     
  22.     static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,  
  23.             int appWidgetId) {  
  24.         CharSequence text;  
  25.         java.text.DateFormat df = new java.text.SimpleDateFormat("hh:mm:ss");  
  26.         text = "http://blog.csdn.net/imyang2007" + "    Time:" + df.format(new Date());  
  27.           
  28.         RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);  
  29.         views.setTextViewText(R.id.appwidget_text, text);  
  30.         appWidgetManager.updateAppWidget(appWidgetId, views);  
  31.     }  
  32.   
  33.   
  34. }  

HelloAppWidgetProvider.java 代码说明

上图是目前的HelloAppWidget范例设计,说明如下:
  • onUpdate(): 收到ACTION_APPWIDGET_UPDATE广播时,框架会callback此method
  • onDelete(): 收到ACTION_APPWIDGET_DELETE广播时,框架会callback此method
  • AppWidgetManager: 管理App Widget的类

在AndroidManifest.xml里我们要让HelloAppWidgetProider类可以接收ACTION_APPWIDGET_UPDATE广播事件;ACTION_APPWIDGET_UPDATE是最主要的App Widget事件,当AppWidgetProvider被要求为App Widget提供”RemoteView”时,就会收到这个事件。

RemoteViews 就是表示UI的类。res/layout/main.xml描述了应用程序的UI,UI里当然包含许多组件(Widget),Android应用程序的UI就是一个View tree,view tree就是View Hierarchy。总结来说,RemotViews是一个用来表示View Hierarchy的类。通过RemoteViews可以找到UI里的每一个组件。

onUpdate()负责更新已经安装在桌面上的App Widget內容,因此我们实现一个updateAppWidget()來进行真正更新的工作。onUpdate()的第二个参数为AppWidgetManager,这是一个管理AppWidgetProvider的类,我们必須通过框架callback本方法时回传给我们的AppWidgetProvider,来更新桌面上的App Widget。onUpdate()第三个参数appWidgetIds阵列,存放需要更新的App Widget ID;框架会将需要更新的App Widget的ID回传给onUpdate(),程序必須负责更新每一个需要更新的App Widget。

updateAppWidget()说明:

  1. 通过UI layout取得自已的「View Hierarchy」(UI),以RemoteViews表示;
  2. 调用RemoteView的setTextViewText()方法,修改UI里的「R.id.appwidget_text」组件,更改文字内容;
  3. 调用AppWidgetProvider的updateAppWidget()方法,更新指定的App Widget,将其UI更新为RemoteView的UI;
  4. updateAppWidget()的第二个参数为RemoteView,即说明1.取得的UI,说明2.修改了此UI里的”R.id.appwidget_text”组件,最后通过App Widget Manager更新App Widget的UI。
App Widget的最后一步,编辑AndroidManifest.xml文件:
[html] view plain copy
  1. xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.android"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk android:minSdkVersion="10" />  
  8.   
  9.     <application  
  10.         android:icon="@drawable/ic_launcher"  
  11.         android:label="@string/app_name" >  
  12.         <receiver android:name=".HelloAppWidgetProvider" >  
  13.             <meta-data  
  14.                 android:name="android.appwidget.provider"  
  15.                 android:resource="@xml/appwidget_provider" />  
  16.   
  17.             <intent-filter>  
  18.                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />  
  19.             intent-filter>  
  20.         receiver>  
  21.   
  22.         <activity  
  23.             android:name=".HelloAppWidgetActivity"  
  24.             android:label="@string/app_name" >  
  25.             <intent-filter>  
  26.                 <action android:name="android.intent.action.MAIN" />  
  27.   
  28.                 <category android:name="android.intent.category.LAUNCHER" />  
  29.             intent-filter>  
  30.         activity>  
  31.     application>  
  32.   
  33. manifest>  

说明如下:
  1. 里加入标签,指定android:name属性为主要的provider类,即”HelloAppWidgetProvider”,注意「.」表示后面的字符串为一个「类别名」,不要忽略了这个重要的小数点
  2. 里加入标签,指定android:resource属性为App Widget的资源名称,就是「@xml/appwidget_provider」,即「xml目录的appwidget_provider.xml文档」
  3. 里加入标签,让App Widget可以接收APPWIDGET_UPDATE事件(event)
至此,一个简单的App Widget设计完成,运行效果为:

最后,发现一个问题,程序并没有实现我们的预想的每秒更新一次App Widget,而是在30~60分钟更新一次,这是1.6之后的android版本为了使设备不那么耗电,把App Widget的更新时间增加到了30分钟以上。

你可能感兴趣的:(Android App Widget设计)