1. 基本信息
App Widget是一种可以被放在其他应用中(如Launcher)并接收周期性更新的应用视图。这些视图在UI上就表现为Widget,并且你可以同App Widget Provider一起发布。
要创建一个App Widget,你需要完成以下步骤:
- AppWidgetProviderInfo对象:它描述了App
Widget的基本元素,比如说布局、更新频率、AppWidgetProvider类等。这些都是在xml文件中定义的。 - 2.AppWidgetProvider类的实现:它定义了一些基本的方法以支持通过广播事件与App Widget交互。通过它,当App Widget被更新、启用、禁用以及删除时,你将收到相应的广播信息。
- 3.View Layout:通过xml文件定义App Widget的初始视图。
2. 添加App Widget布局
另外,你还可以实现一个App Widget的配置Activity。当然,这不是强制的。
要创建你的App Widget的初始布局,你可以使用以下View对象。
创建布局不是很麻烦,重点是,你必须记住,这个布局是基于RemoteViews的,不是所有的布局类型与View都支持。
一个RemoteViews对象可以支持以下布局类:
FrameLayout | LinearLayout | RelativeLayout |
AnalogClock | Button | Chronometer | ImageButton |
ImageView | ProgressBar | TextView | ViewFlipper |
注:这些类的子类是不支持的。
res/layout文件夹下创建widget.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="当前时间" android:textColor="@android:color/white" android:textSize="18sp" android:id="@+id/tv_weather"/>
</LinearLayout>
3. 添加AppWidgetProviderInfo元数据
res/xml文件夹下创建weather.xml文件
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="294dp"
android:minHeight="72dp"
android:updatePeriodMillis="86400000"
android:previewImage="@drawable/preview"
android:initialLayout="@layout/widget"
android:configure="com.example.android.ExampleAppWidgetConfigure"
android:resizeMode="horizontal|vertical">
</appwidget-provider>
minWidth与minHeight属性表示了App Widget所需的最小布局区域。
默认的主屏中,App Widget要想确认其位置,需要通过基于网格的具有固定宽度和高度的单元。如果App Widget的最小宽度和高度无法匹配给定的单元,它将会自动扩展到最接近的单元大小。
由于主屏的布局方向是可变的,你应该考虑最坏的情况(每单元的宽和高都是74dp)。然而,为了防止在扩展时产生整数计算错误,你还需要减去2。因此,你可以用以下公式来计算最小宽度和高度(单位dp):(单元数量×74)-2。
同时,为了保证你的App Widget能够在各种设备上正常使用,它们的宽度和高度必须不超过4×4个单元。updatePeriodMillis属性定义了App
Widget框架调用AppWidgetProvider的onUpdate方法的频率。对于实际的更新,我们不建议采用该值进行实时处理。最好是越不频繁越好——为了保证电量,一小时不超过一次为好。当然,你也可以允许用户对更新频率进行设置。
注意,如果更新触发时设备正处于休眠状态,设备将唤醒以执行该操作。如果你的更新频率不超过一小时一次,这不会对电池的寿命产生多大的影响。但如果你需要更频繁地更新却又不想要在设备休眠时执行,那你可以使用定时器来执行更新。要达到这种目的,可以在AlarmManager中设置一个AppWidgetProvider能接收的Intent。将类型设为ELAPSED_REALTIME或RTC。由于AlarmManager只有当设备处于唤醒状态时才会被调用,我们只要设updatePeriodMillis为0即可。- linitialLayout属性标识了初始布局文件。
- configure属性定义了当用户添加App Widget时调用的Activity。(这是可选的)
- previewImage定义了App
Widget的缩略图,当用户从widget列表中选择时,显示的就是这张图。如果没设置,用户将看见的是你的应用的默认图标。 - autoAdvanceViewId属性是在Android3.0引入的,用于标识需要被host(launcher)自动更新的widget的子视图。
- resizeMode属性标识了widget重新布局的规则。你可以使用该属性来让widget能够在水平、竖直、或两个方向上均可变化。可用的值包括horizontal、vertical、none。如果是想在两个方向上均能拉伸,可设置为horizontal|vertical,当然,需要Android3.1以上版本。
4. 使用AppWidgetProvider类
public class ClockProvider extends AppWidgetProvider {
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
Intent _intent = new Intent(context, ClockService.class);
context.startService(_intent);
}
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
Intent _intent = new Intent(context, ClockService.class);
context.stopService(_intent);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}
onUpdate()
由updatePeriodMills定义的时间间隔触发。当然,添加Widget的时候也会,因此,应该在此处执行一些必要的配置,如定义View的事件处理handler,有必要的话,还会启动一个临时的Service。然而,如果你声明了一个配置Activity,该方法将不会在此时被调用。onDelete(Context, int[])
当App Widget从host中移除时会被调用。- onEnabled(Context)
当App Widget的实例被第一次创建时,该方法将被调用。如果你建了两个实例,那该方法也只会被调用一次。 onDisabled(Context)
当最后一个App Widget的实例被删除时,该方法被调用。你可以在此处清除之前在onEnabled里执行的操作。onReceive(Content, Intent)
每次接收到广播都会被调用,而且执行的顺序在上述方法之前。通常,你不需要实现该方法,因为AppWidgetProvider已经对各种不同类型的广播进行了过滤及分发。
注:在Android1.5中,有一个已知的问题,使得在某些情况下,onDeleted不会被调用。这时,你就需要实现onReceive()了。
5. 使用Service更新数据
public class ClockService extends Service implements AMapLocalWeatherListener {
private LocationManagerProxy mLocationManagerProxy;
public SimpleDateFormat sdf;
public Timer timer;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
System.out.println("start");
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
String time = sdf.format(new Date());
updateViews(time);
}
},0,1000);
}
private void updateViews(String info)
{
Intent _intent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, _intent, 0);
RemoteViews views = new RemoteViews(getPackageName(), R.layout.widget);
views.setTextViewText(R.id.tv_weather, info);
views.setOnClickPendingIntent(R.id.tv_weather, pendingIntent);//点击跳到主页
AppWidgetManager manager = AppWidgetManager.getInstance(this);
ComponentName name = new ComponentName(this, ClockProvider.class);
manager.updateAppWidget(name,views);
}
@Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
}
}
通过RemoteViews类和AppWidgetManager类发送广播更新界面数据
6.在AndroidManifest中声明一个App Widget
<service android:name=".ClockService"></service>
<receiver android:name=".ClockProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"></action>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/weather"></meta-data>
</receiver>
meta-data标签标识了AppWidgetProviderInfo资源,它需要以下属性:
android:name:使用android.appwidget.provider来标识AppWidgetProviderInfo。
android:resource:标识AppWidgetProviderInfo的资源位置。