安卓开发之 App Widget

来源:互联网 发布:软件开发项目生命周期 编辑:程序博客网 时间:2024/04/30 21:04

一、什么是App Widget

Android平台上在桌面上所放置的一种小控件

与App Widget相关的类/对象:

  1. AppWidgetProviderInfo对象:

    定义App Widget的一些信息,为App Widget提供元数据,包括App Widget布局文件的指定,更新频率等数据。这个对象被定义在XML文件当中,其相对于一个Config配置“文件”.
  2. AppWidgetProvider:

    继承自BroadcastReicever广播接收器。定义了App Widget的基本生命周期的回调函数.

二、创建一个App Widget的步骤

一、定义AppWidgetProviderInfo:

  1. res/xml文件夹当中定义描述AppWidgetProviderInfo的xml文件。

    例:…\res\xml\appwidget_info.xml

    <?xml version="1.0" encoding="utf-8"?><appwidget-provider     xmlns:android="http://schemas.android.com/apk/res/android"    android:minHeight="60dp"    android:minWidth="200dp"    android:previewImage="@drawable/default_img"    android:resizeMode="horizontal|vertical"    android:updatePeriodMillis="40000"    android:initialLayout="@layout/appwidget_layout" ></appwidget-provider>

    updatePeriodMillis为更新的毫秒数、initialLayout为初始化的widget布局;
    previewImage为该app widget的预览图,在桌面小部件选择时显示;
    resizeMode:app widget 在水平和垂直方向是否可以调整大小。

二、为App Widget指定布局:

  1. 定义App Widget展示时的布局文件appwidget_layout

    例:…\res\layout\appwidget_layout.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"    android:background="#00000000"    >    <TextView        android:id="@+id/widget_text"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:gravity="center_horizontal"        android:text="widget text"        />    <Button        android:id="@+id/widget_button"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:gravity="center_horizontal"        android:text="widget button"        /></LinearLayout>

三、实现AppWidgetProvider

  • onUpdate:在到达指定的更新时间之后或者当用户向桌面添加App Widget时会调用该方法

  • onDeleted:在App Widget被删除时,会调用该方法

  • onEnable:当一个App Widget的实例第一次被创建时,会调用该方法

  • onDisable:当最后一个App Widget实例被删除后,会调用该方法

  • onReceive:监听/接收广播事件,可用于处理控件的点击事件等

(桌面上可以有多个同样的app widget)

例:

public class MyAppWidgetProvider extends AppWidgetProvider {    @Override    public void onReceive(Context context, Intent intent) {        super.onReceive(context, intent);    }    @Override    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {        super.onUpdate(context, appWidgetManager, appWidgetIds);    }    @Override    public void onDeleted(Context context, int[] appWidgetIds) {        super.onDeleted(context, appWidgetIds);    }    @Override    public void onEnabled(Context context) {        super.onEnabled(context);    }    @Override    public void onDisabled(Context context) {        super.onDisabled(context);    }}

因AppWidgetProvider又继承自BroadcastReceiver,所以需要在AndroidManifest中注册:

    <receiver android:name=".MyAppWidgetProvider">        <intent-filter>            <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>        </intent-filter>        <meta-data android:name="android.appwidget.provider"            android:resource="@xml/appwidget_info"/>    </receiver>

其中action是引用android自定义的action,meta-data为元数据:resource为说明该App Widget 的配置信息的xml文件,name必须是android.appwidget.provider。

三、使用App Widget布局中的控件

>使用App Widget布局中的控件其中涉及到了PendingIntent,RemoteViews..

一、PendingIntent

Pending:待处理的。PendingIntent 可以看作为一种“留待日后处理”的意图,是对Intent的一种包装,创建之后并不马上使用,一旦某种触发事件的发生,意图才马上执行。

  1. App Widget和应用程序并不是在同一进程当中。
  2. 创建PendingIntent对象的三个静态方法:

    • getActivity(Context context, int requestCode, Intent intent, int flags)
    • getBroadcast(Context context, int requestCode, Intent intent, int flags)
    • getService(Context context, int requestCode, Intent intent, int flags)

    根据PeningIntent具体发送/启动(广播/Activity/服务)来选择对应的一个静态方法来创建PendingIntent对象。

二、RemoteViews的作用

RemoteViews:远程控件。App Widget里的控件和主程序不在同一进程中,所以App Widget里的控件相对于一种远程控件。

  1. RemoteViews对象表示了一系列的View对象。
  2. RemoteViews所表示的对象运行在另外的进程中。
  3. App Widget当中的View运行在Home Screen进程当中。

三、操作AppWidget的Button

由于AppWidget的Button不与主程序在同一进程中,所以无法按照之前惯用的方法给Button绑定监听器。

为AppWidget的Button绑定监听器:

新方法:remoteViews.setOnClickPendingIntent(R.id.widget_button, pendingIntent);
第一个参数为AppWidget的Button的id,第二参数为PendingIntent对象。
当Button被点击时,会引起pendingIntent的执行。

例:重新实现AppWidgetProvider:点击Button时启动Activity

public class MyAppWidgetProvider extends AppWidgetProvider {    @Override    public void onReceive(Context context, Intent intent) {        super.onReceive(context, intent);        Log.i("z","onReceive");    }    @Override    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {        super.onUpdate(context, appWidgetManager, appWidgetIds);        // appWidgetMahager:管理app widget        // appWidgetIds : appWidget的id数组(桌面可放置多个同样的小部件)        for (int i= 0;i< appWidgetIds.length;i++){            //给每一个小部件的按钮绑定监听器            Log.i("z",appWidgetIds[i]+" ");            //创建一个Intent对象            Intent intent = new Intent(context,MainActivity.class);            //包装成一个PendingIntent对象            PendingIntent pendingIntent = PendingIntent.getActivity(context,0,intent,0);            //得到RemoteViews对象            RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.appwidget_layout);            //给app widget中的Button绑定监听器            remoteViews.setOnClickPendingIntent(R.id.widget_button,pendingIntent);            //更新app widget            appWidgetManager.updateAppWidget(appWidgetIds[i],remoteViews);        }    }    @Override    public void onDeleted(Context context, int[] appWidgetIds) {        super.onDeleted(context, appWidgetIds);        Log.i("z","onDeleted");    }    @Override    public void onEnabled(Context context) {        super.onEnabled(context);        Log.i("z","onEnabled");    }    @Override    public void onDisabled(Context context) {        super.onDisabled(context);        Log.i("z","onDisabled");    }}

四、接收来自AppWidget的广播和更新控件的状态

  1. 在AndroidManifest当中为AppWidgetProvider注册新的intent-filter,配置所要接收的广播行为。AppWidgetProvider本质上是一个广播接收器

  2. 使用getBroadcast(…)方法创建一个发送广播PendingIntent。

  3. 为AppWidget当中的控件注册处理器,用来触发发送广播的行为。

  4. 在onReceive方法当中接收来自AppWidget发送的广播消息,并执行自己的业务逻辑,使用RemoteViews对象更新App Widget当中的控件状态。

  5. AppWidgetProvider的运行机制:通过onReceive来接收广播,接收到特定的系统内置广播时来调用onUpdate(..)等生命周期的回调方法,由onReceive来调用生命周期函数。

例:重新在AndroidMainfest注册AppWidgerProvider:

    <receiver android:name=".MyAppWidgetProvider">        <intent-filter>            <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>        </intent-filter>        <intent-filter>            <action android:name="my.appwidget.Text_UPDATE"/>        </intent-filter>        <meta-data android:name="android.appwidget.provider"            android:resource="@xml/appwidget_info"/>    </receiver>

“android.appwidget.action.APPWIDGET_UPDATE”:系统自带广播,用来接收后回调声明周期函数。
“my.appwidget.Text_UPDATE”:自定义广播,用来接收后进行对TextView的操作。

重新实现AppWidgetProvider:

public class MyAppWidgetProvider extends AppWidgetProvider {    private static final String TEXT_UPDATE = "my.appwidget.Text_UPDATE";    @Override    public void onReceive(Context context, Intent intent) {        super.onReceive(context, intent);        if(intent!=null&& TextUtils.equals(TEXT_UPDATE,intent.getAction())){            Log.i("z","onReceiveTextUpdate");            //获取app widget的所有控件            RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.appwidget_layout);            //设置TextView的文本            remoteViews.setTextViewText(R.id.widget_text,"Changed Text");            //获取app widget的管理器            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);            //获取app widget的对象            ComponentName componentName = new ComponentName(context,MyAppWidgetProvider.class);            //管理器更新app widget            appWidgetManager.updateAppWidget(componentName,remoteViews);        }    }    @Override    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {        super.onUpdate(context, appWidgetManager, appWidgetIds);        // appWidgetMahager:管理app widget        // appWidgetIds : appWidget的id数组(桌面小部件可重复放置多个小部件)        for (int i= 0;i< appWidgetIds.length;i++){            Log.i("z",appWidgetIds[i]+" ");            //创建一个发送广播的Intent对象,并设置action            Intent intent = new Intent();            intent.setAction(TEXT_UPDATE);            //包装成一个PendingIntent对象,执行时会发送一个广播。            PendingIntent pendingIntent = PendingIntent.getBroadcast(context,0,intent,0);            //得到RemoteViews对象            RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.appwidget_layout);            //给app widget中的Button绑定监听器            remoteViews.setOnClickPendingIntent(R.id.widget_button,pendingIntent);            //更新app widget            appWidgetManager.updateAppWidget(appWidgetIds[i],remoteViews);        }    }    @Override    public void onDeleted(Context context, int[] appWidgetIds) {        super.onDeleted(context, appWidgetIds);        Log.i("z","onDeleted");    }    @Override    public void onEnabled(Context context) {        super.onEnabled(context);        Log.i("z","onEnabled");    }    @Override    public void onDisabled(Context context) {        super.onDisabled(context);        Log.i("z","onDisabled");    }}
1 0
原创粉丝点击