首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

圆桌面小部件AppWidget的使用

2013-03-01 
桌面小部件AppWidget的使用在android平台中,显示在HOME界面的一些挂件,即桌面小部件,被称为AppWidget。在自

桌面小部件AppWidget的使用
在android平台中,显示在HOME界面的一些挂件,即桌面小部件,被称为AppWidget。在自己的程序中适当地加入AppWidget,不但使用户更方便,也能从一定程序上提高本程序的留存率。

下面通过我所写的一个课表应用来说明如何使用AppWidget。
我所写的AppWidget最终结果如下图:



1.首先在res/layout下编写AppWidget的布局文件。
我的代码如下:
appwidget_small.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="60dp"    android:background="@drawable/appwidget_bg" >    <Button        android:id="@+id/widget_small_refresh"        android:layout_width="60dp"        android:layout_height="40dp"        android:layout_alignParentRight="true"        android:text="@string/widget_small_refrest"        android:textAppearance="@android:style/TextAppearance.Medium" />    <TextView        android:id="@+id/widget_small_day"        android:layout_width="60dp"        android:layout_height="match_parent"        android:layout_alignParentRight="true"        android:layout_below="@id/widget_small_refresh"        android:gravity="center"        android:textAppearance="@android:style/TextAppearance.Small" />    <include        android:id="@+id/widget_small_content"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_marginBottom="2dp"        android:layout_marginLeft="2dp"        android:layout_marginTop="2dp"        android:layout_toLeftOf="@id/widget_small_refresh"        layout="@layout/main_list_item"        android:background="@drawable/appwidget_list_bg" /></RelativeLayout>

其中include的是课表信息部分的布局,它在我的MainActivity还用到,这里没有另外编写,直接使用include标签将它引用进来。
main_list_item.xml的代码如下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:orientation="horizontal" >    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:orientation="vertical" >        <TextView            android:id="@+id/list_item_class"            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:gravity="center"            android:singleLine="true"            android:textAppearance="@android:style/TextAppearance.Medium" />        <TextView            android:id="@+id/list_item_time"            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:gravity="center"            android:singleLine="true"            android:textAppearance="@android:style/TextAppearance.Small" />    </LinearLayout>    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="wrap_content" >        <LinearLayout            android:layout_width="120dp"            android:layout_height="wrap_content"            android:layout_weight="2"            android:orientation="vertical" >            <TextView                android:id="@+id/list_item_course"                android:layout_width="fill_parent"                android:layout_height="wrap_content"                android:gravity="center"                android:singleLine="true"                android:textAppearance="@android:style/TextAppearance.Medium" />            <TextView                android:id="@+id/list_item_teacher"                android:layout_width="fill_parent"                android:layout_height="wrap_content"                android:gravity="center"                android:singleLine="true"                android:textAppearance="@android:style/TextAppearance.Medium" />        </LinearLayout>        <LinearLayout            android:layout_width="120dp"            android:layout_height="wrap_content"            android:layout_weight="2"            android:orientation="vertical" >            <TextView                android:id="@+id/list_item_room"                android:layout_width="fill_parent"                android:layout_height="wrap_content"                android:gravity="center"                android:singleLine="true"                android:textAppearance="@android:style/TextAppearance.Medium" />            <TextView                android:id="@+id/list_item_week"                android:layout_width="fill_parent"                android:layout_height="wrap_content"                android:gravity="center"                android:singleLine="true"                android:textAppearance="@android:style/TextAppearance.Medium" />        </LinearLayout>    </LinearLayout></LinearLayout>

在这里说明一下,对于appWidget的布局文件的根标签如果设置宽高为match_parent(fill_partent),则在HOME界面改变它的大小时它也会自动扩张,否则无论将它占的空间拉伸到多大,它都不会扩张。

2.在/res/xml下编写这个appwidget的信息文件。
widget_small_provider_info.xml代码如下:
<?xml version="1.0" encoding="UTF-8"?><appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"    android:initialLayout="@layout/appwidget_small"    android:minHeight="60dp"    android:minWidth="240dp"    android:updatePeriodMillis="1800000" ></appwidget-provider>

上面initialLayout即初始的布局,minHeight和minWidth即最小的宽高,updatePeriodMillis为更新周期。
需要注意的是关于这个更新周期,在我本机G14,android4.0.3上发现它并没有用,百度之后发现它存在着BUG,在有些系统有效,有些则没效。所以如果想在任何机型都能自动更新的话,还要自己写一个service去更新。这个可参考android SDK中的例子。

3.接下来需要编写一个类,继承自AppWidgetProvider。
代码如下:
/* * @(#)TableWidgetProvider.java       Project:UniversityTimetable * Date:2013-2-11 * * Copyright (c) 2013 CFuture09, Institute of Software,  * Guangdong Ocean University, Zhanjiang, GuangDong, China. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); *  you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.lurencun.cfuture09.universityTimetable.appwidget;import java.util.Calendar;import android.app.PendingIntent;import android.appwidget.AppWidgetManager;import android.appwidget.AppWidgetProvider;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.database.Cursor;import android.util.Log;import android.widget.RemoteViews;import com.lurencun.cfuture09.universityTimetable.R;/** * @Author Geek_Soledad (66704238@51uc.com) * @Function */public class TableSmallWidgetProvider extends AppWidgetProvider {private static final String TAG = "TableSmallWidgetProvider";public static final String ACTION_UPDATE = "cfuture09.universityTimetable.action.TIMETABLE.APPWIDGET_SMALL_UPDATE";@Overridepublic void onDeleted(Context context, int[] appWidgetIds) {super.onDeleted(context, appWidgetIds);Log.d(TAG, "onDeleted");}@Overridepublic void onDisabled(Context context) {super.onDisabled(context);Log.d(TAG, "onDisable");}@Overridepublic void onEnabled(Context context) {super.onEnabled(context);Log.d(TAG, "onEnabled");}@Overridepublic void onReceive(Context context, Intent intent) {super.onReceive(context, intent);Log.d(TAG, "onReceive");}@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {super.onUpdate(context, appWidgetManager, appWidgetIds);Log.d(TAG, "update");}}

上面onEnabled在第一次创建AppWidget中执行。
在HOME界面中是可以多次插入同一个AppWidget的,每次插入一个AppWidget,onReceive和onUpdate都会被执行,这一次可以自己去做试验了解它的生命周期,在这里不赘述。

4.在Manifest中声明。
<receiver            android:name=".appwidget.TableSmallWidgetProvider"            android:label="@string/widget_small_4_1" >            <intent-filter>                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />            </intent-filter>            <intent-filter>                <action android:name="cfuture09.universityTimetable.action.TIMETABLE.APPWIDGET_SMALL_UPDATE" />            </intent-filter>            <meta-data                android:name="android.appwidget.provider"                android:resource="@xml/widget_small_provider_info" />        </receiver>
其中label中引用的字符串即在插入Appwidget时出现的那个名字,如这里为"大学课程表(4*1)",如果不添加,默认为你的程序名,即在application标签中声明的label。然后加入的intent-filter,为其接收的广播,这里还定义了自己的一个action,它将在下面的例子中用到,因为我希望还能手动更新appwidget的数据。

在上面的例子中,一个简单的AppWidget就完成了。

但是我需要的还不够,我还希望这个AppWidget的控件内容是可以改变的,而不是写死在布局文件中的,这就需要用到RemoteViews了。
因为在android中,AppWidget与你的主程序是运行在不同的进程当中的,在这里需要用RemoteViews来进行它们之间的通信,而不是像在Activity中那样方便。
而对于RemoteViews在不同版本的API中,支持的控件(亦其提供的方法)也不同,越往后支持的越多,在2.2中,貌似还不支持AbsListView控件的更新,也只提供了简单的onclick事件绑定的方法。

首先创建一个RemoteViwews对象,RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget_small);
然后可以通过它的setTextViewText方法设置AppWidget中的TextView的内容,传入的参数为要设置的textview的id和内容。
如果想点击它而打开你的程序的activity,或者更新控件,则也如下面代码所示。
@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {super.onUpdate(context, appWidgetManager, appWidgetIds);Log.d(TAG, "onUpdate");for (int i = 0; i < appWidgetIds.length; i++) {RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.appwidget_small);// 设置星期几remoteViews.setTextViewText(R.id.widget_small_day,arrayWeeks[currentDay]);// 打开程序PendingIntent startIntent = PendingIntent.getActivity(context, 0,new Intent(context, MainActivity.class), 0);remoteViews.setOnClickPendingIntent(R.id.widget_small_content,startIntent);// 更新控件的事件绑定Intent intent = new Intent();intent.setAction(ACTION_UPDATE);// 以发送广播消息的方式创建PendingIntent.PendingIntent pending_intent = PendingIntent.getBroadcast(context,0, intent, 0);remoteViews.setOnClickPendingIntent(R.id.widget_small_refresh,pending_intent);appWidgetManager.updateAppWidget(appWidgetIds[i], remoteViews);}}

在更新控件中,由于它是发送了一个广播,onReceive将会被执行,但不会执行onUpdate方法,所以这里还需要再修改onReceive方法,否则无法达到更新的目的。
@Overridepublic void onReceive(Context context, Intent intent) {Log.d(TAG, "onReceive");if (ACTION_UPDATE.equals(intent.getAction())) {RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.appwidget_small);// 设置星期几remoteViews.setTextViewText(R.id.widget_small_day,arrayWeeks[currentDay]);// 更新节课updateWidgetViews(remoteViews, dto);PendingIntent startIntent = PendingIntent.getActivity(context, 0,new Intent(context, MainActivity.class), 0);remoteViews.setOnClickPendingIntent(R.id.widget_small_content,startIntent);ComponentName componentName = new ComponentName(context,TableSmallWidgetProvider.class);AppWidgetManager.getInstance(context).updateAppWidget(componentName, remoteViews);} else {super.onReceive(context, intent);}}

热点排行