App Widget

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
以及一下widget类
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的资源位置。

你可能感兴趣的:(appwidget)