桌面小部件App widget的使用

AppWidget(窗口小部件)是基于BroadcastReceiver组件机制再开发而来的,为此他首先需要遵循BroadcastReceiver的开发流程进行开发,其次是根据他自身提供的AppWidgetProvider、AppWidgetProvderInfo、AppWidgetManger来进行开发。为此要开发一个AppWidget大致流程如下:

1.在res文件夹中新建一个xml文件:(该文件名在下面的第四步有用到,作为appWidget的资源)

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="200dp"
    android:minHeight="50dp"
    android:updatePeriodMillis="0"
    android:initialLayout="@layout/appwidget_layout"
     > 
</appwidget-provider>

属性说明:

updatePeriodMillis:定义了App Widget框架调用AppWidgetProvider(继承该类的类)的onUpdate方法的频率,google建议这个值设置为最小1小时,否则设备会被频繁唤醒,而且还建议如果要设置短时的更新时间,推荐使用AlarmManager类中的工具来调用onUpdate。这里该值设置为0,则表示不进行对onUpdate的更新调用,只在添加到桌面时调用。

initialLayout 属性标识了初始布局文件(显示在桌面的布局文件)

configure 属性定义了当用户添加App Widget时调用的Activity。

previewImage定义了App Widget的缩略图,当用户从widget列表(安卓4.1的窗口小部件)中选择时,显示的就是这张图。如果没设置,用户将看见的是你的应用的默认图标。

resizeMode 属性标识了widget重新布局的规则。你可以使用该属性来让widget能够在水平、竖直、或两个方向上均可变化。可用的值包括horizontal、vertical、none。如果是想在两个方向上均能拉伸,可设置为horizontal|vertical,当然,需要Android3.1以上版本。

2.在layout文件夹中新建布局文件作为第一步中initialLayout方法中所指定的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="显示在桌面的widget" />
</LinearLayout>

说明:这里只在桌面上显示一行文字。

3.自定义一个类继承 AppWidgetProvider,代码如下:

public class MyAppWidget extends AppWidgetProvider {
    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        System.out.println("接收receiver中注册的广播事件时调用该方法");
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        System.out.println("在达到指定的更新时间之后或者当用户向桌面添加App Widget时会调用该方法");
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        super.onDeleted(context, appWidgetIds);
        System.out.println("当App Widget被删除时,会调用该方法");
    }

    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
        System.out.println("当一个App Widget的实例第一次被创建时,会调用该方法");
    }

    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
        System.out.println("当最后一个App Widget实例被删除后,会调用该方法");
    }
    
}

4.在AndroidManifest.xml文件中对app Widget(和广播类似)进行注册:

 <receiver android:name="MyAppWidget"
            android:label="terst"
            android:icon="@drawable/ic_launcher">
            <intent-filter >
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> //接收该广播,系统的widget广播 还可以在receiver中继续添加自定义广播等等
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"   //标识appwidget使用的资源
                android:resource="@xml/appwidget_info"/>      //指定资源文件 也就是上面步骤中我们新建的xml文件夹中的appwidget.xml文件
        </receiver>

说明:

<receiver>标签name 用于指明App Widget使用的AppWidgetProvider(被继承的类)

label 和 icon用于指定在窗口小部件中显示文字和图标

效果如下:

 

当我们从窗口小部件中拖拽到桌面上显示时,效果如下:

 但是   注意点:

由于App Widget和我们的应用程序运行在不同的进程当中(App Widget当中的View运行在Home Screen主屏幕进程当中),
所以,无法按照之前的惯用的方法绑定监听器,那么怎么添加按钮且监听呢?看下面的代码:

1.首先在App Widget桌面显示的布局文件中加入按钮:

appwidget_layout.xml中加入:

<Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_widget"
        android:text="桌面显示的按钮" />

2.添加按钮监听器:

在重写的onUpdate方法中添加如下代码:

@Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        System.out.println("在达到指定的更新时间之后或者当用户向桌面添加App Widget时会调用该方法");
        //绑定监听,因为只有在拖拽到桌面上才需要监听
        for(int i=0;i<appWidgetIds.length;i++){//appWidgetIds里面装的是拖拽出来的所有widget
            System.out.println("远程视图需要的包名:"+context.getPackageName());
            //不能直接设置监听,所以需要通过远程视图进行设置,appwidget_layout为显示在桌面的视图
            RemoteViews rv=new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);
            PendingIntent intent=PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);//转到MainActivity
            rv.setOnClickPendingIntent(R.id.btn_widget, intent);//为btn_widget设置单击事件为intent
            appWidgetManager.updateAppWidget(appWidgetIds[i], rv);//更新数据到这个小部件
        }//为每个拖拽出来的小部件设置单击事件
    }

说明:为widget中的按钮添加单击事件需要通过RemoteViews远程视图类作为中间者添加监听,最后要使用appWidgetManager实现更新数据。

效果如下:

 

说明:当点击按钮时就会跳转到MainActivity类

在桌面显示的按钮可以通过RemoteViews来设置,那么其他的组件呢?代码如下,通过按钮发送广播,接收后改变文本控件显示的内容     代码都是在上面的代码中进行添加的

1.在AndroidManifest.xml文件中注册自定义广播(因为按钮在widget中,所以需要在widget中注册):

 <receiver android:name="MyAppWidget"
            android:label="terst"
            android:icon="@drawable/ic_launcher">
            <intent-filter >
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/appwidget_info"/>
            <intent-filter >
                <action android:name="myBroadcast"/>   //添加的自定义广播
            </intent-filter>
 </receiver>

2.在(桌面显示的布局)appwidget_layout.xml文件中添加了一个按钮,如下:

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_sendBroad"
android:text="发送广播" />

3.MyAppWidget.java类中的代码:

public class MyAppWidget extends AppWidgetProvider {
    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        System.out.println("接收广播事件");
        String action = intent.getAction();//获取活动,xml文件中注册的广播
        if(action.equals("myBroadcast")){
            System.out.println("接收到自定义的广播");
            //通过RemoteViews对象改变布局中的组件内容
            RemoteViews rv=new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);
            rv.setTextViewText(R.id.text, "接收广播后改变文本内容");//修改id为text的内容为~   修改图片也是同样的道理
            ComponentName componentName=new ComponentName(context, MyAppWidget.class);//因为这里没有appWidgetIds对象,所以需要这样更新数据
            AppWidgetManager.getInstance(context).updateAppWidget(componentName, rv);//更新数据
        }
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        System.out.println("在达到指定的更新时间之后或者当用户向桌面添加App Widget时会调用该方法");
        //绑定监听,因为只有在拖拽到桌面上才需要监听
        for(int i=0;i<appWidgetIds.length;i++){//appWidgetIds里面装的是拖拽出来的所有widget
            System.out.println("远程视图需要的包名:"+context.getPackageName());
            //不能直接设置监听,所以需要通过远程视图进行设置,appwidget_layout为显示在桌面的视图
            RemoteViews rv=new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);//相当于桌面显示的布局文件
            PendingIntent intent=PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);//转到MainActivity
            rv.setOnClickPendingIntent(R.id.btn_widget, intent);//为btn_widget设置单击事件为intent
            //为发送广播的按钮设置单击事件,点击后发送一条自定义的广播
            rv.setOnClickPendingIntent(R.id.btn_sendBroad, PendingIntent.getBroadcast(context, 0, new Intent("myBroadcast"), 0));
            appWidgetManager.updateAppWidget(appWidgetIds[i], rv);//更新数据到这个小部件
        }//为每个拖拽出来的小部件设置单击事件
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        super.onDeleted(context, appWidgetIds);
        System.out.println("当App Widget被删除时,会调用该方法");
    }

    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
        System.out.println("当一个App Widget的实例第一次被创建时,会调用该方法");
    }

    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
        System.out.println("当最后一个App Widget实例被删除后,会调用该方法");
    }
    
}

效果如下:当点击发送广播按钮时会将文本显示内容改掉

posted @ 2016-05-09 14:41  ts-android  阅读(593)  评论(0编辑  收藏  举报