Android桌面组件widget初探是本文要介绍的内容,主要是来了解Android Widget 的应用,本来打算晚上继续ApiDemos系列的,不过今天下午的时候无聊去玩了一下桌面组件AppWidget觉得挺不错的一个东西,对它很是感兴趣,玩了一下碰到很多问题,一直在解决问题到了晚上10点。只能怪自己理解不深刻,不过最后还是解决了,把一些领悟写出来也算给自己一个交代。下面是本篇的大纲:
1、AppWidget框架类
2、在Android如何使用Widget
3、AppWidget框架的主要类介绍
4、DEMO讲解
1、AppWidget框架类
1、AppWidgetProvider:继承自BroadcastRecevier,在AppWidget应用update、enable、disable和delete时接收通知。其中,onUpdate、onReceive是最常用到的方法,它们接收更新通知。
2、AppWidgetProvderInfo:描述AppWidget的大小、更新频率和初始界面等信息,以XML文件形式存在于应用的res/xml/目录下。
3、AppWidgetManger:负责管理AppWidget,向AppwidgetProvider发送通知。
4、RemoteViews:一个可以在其他应用进程中运行的类,向AppWidgetProvider发送通知。
2、在Android如何使用Widget
1、长按主界面

2、之后弹出一个对话框,里面就有android内置的一些桌面组件

3、AppWidget框架的主要类介绍
1)AppWidgetManger类
bindAppWidgetId(intappWidgetId,ComponentNameprovider)
- 1.
通过给定的ComponentName绑定appWidgetId
getAppWidgetIds(ComponentNameprovider)
- 1.
通过给定的ComponentName获取AppWidgetId
getAppWidgetInfo(intappWidgetId)
- 1.
通过AppWidgetId获取AppWidget信息
getInstalledProviders()
- 1.
返回一个List的信息
getInstance(Contextcontext)
- 1.
获取AppWidgetManger实例使用的上下文对象
updateAppWidget(int[]appWidgetIds,RemoteViewsviews)
- 1.
通过appWidgetId对传进来的RemoteView进行修改,并重新刷新AppWidget组件
updateAppWidget(ComponentNameprovider,RemoteViewsviews)
- 1.
通过ComponentName对传进来的RemoeteView进行修改,并重新刷新AppWidget组件
updateAppWidget(intappWidgetId,RemoteViewsviews)
- 1.
通过appWidgetId对传进来的RemoteView进行修改,并重新刷新AppWidget组件
2)继承自AppWidgetProvider可实现的方法为如下:
1、
onDeleted(Contextcontext,int[]appWidgetIds)
- 1.
2、
onDisabled(Contextcontext)
- 1.
3、
onEnabled(Contextcontext)
- 1.
4、
onReceive(Contextcontext,Intentintent)
- 1.
Tip:因为AppWidgetProvider是继承自BroadcastReceiver所以可以重写onRecevie方法,当然必须在后台注册Receiver
5、
onUpdate(Contextcontext,AppWidgetManagerappWidgetManager,int[]appWidgetIds)
- 1.
4、Demo讲解
下面是我今天做的一个实例,提供给大家练习时做参考,效果如下:在布局中放一个TextView做桌面组件,然后设置TextView的Clickable="true"使其有点击的功能,然后我们点击它时改变它的字体,再点击时变回来,详细操作如下流程:
1、新建AppWidgetProvderInfo
2、写一个类继承自AppWidgetProvider
3、后台注册Receiver
4、使AppWidget组件支持点击事件
5、如何使TextView在两种文本间来回跳转
问题抛出来了,那么一起解决它吧。
1、新建AppWidgetProvderInfo
代码如下:
android:minWidth="60dp"
android:minHeight="30dp"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/main">
- 1.
- 2.
- 3.
- 4.
Tip:上文说过AppWidgetProvderInfo是在res/xml的文件形式存在的,看参数不难理解,比较重要的是这里android:initialLayout="@layout/main"此句为指定桌面组件的布局文件。
2、写一个类继承自AppWidgetProvider
主要代码如下:
public class widgetProvider extends AppWidgetProvider
- 1.
并重写两个方法
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {}
@Override
public void onReceive(Context context, Intent intent) {}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
Tip:onUpdate为组件在桌面上生成时调用,并更新组件UI,onReceiver为接收广播时调用更新UI,一般这两个方法是比较常用的。
3、后台注册Receiver
后台配置文件代码如下:
<receiver android:name=".widgetProvider">
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/appwidget_provider"></meta-data>
<intent-filter>
<action android:name="com.terry.action.widget.click"></action>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
</receiver>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
Tip:因为是桌面组件,所以暂时不考虑使用Activity界面,当然你在实现做项目时可能会需要点击时跳转到Activity应用程序上做操作,典型的案例为Android提供的音乐播放器。上面代码中比较重要的是这一句大意为指定桌面应用程序的AppWidgetProvderInfo文件,使其可作其管理文件。
4、使AppWidget组件支持点击事件
先看代码:
public static void updateAppWidget(Context context,
AppWidgetManager appWidgeManger, int appWidgetId) {
rv = new RemoteViews(context.getPackageName(), R.layout.main);
Intent intentClick = new Intent(CLICK_NAME_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
intentClick, 0);
rv.setOnClickPendingIntent(R.id.TextView01, pendingIntent);
appWidgeManger.updateAppWidget(appWidgetId, rv);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
此方法为创建组件时onUpdate调用的更新UI的方法,代码中使用RemoteView找到组件的布局文件,同时为其设置广播接收器CLICK_NAME_ACTION并且通过RemoteView的setOnClickPendingIntent方法找到我想触发事件的TextView为其设置广播。接着
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
super.onReceive(context, intent);
if (rv == null) {
rv = new RemoteViews(context.getPackageName(), R.layout.main);
}
if (intent.getAction().equals(CLICK_NAME_ACTION)) {
if (uitil.isChange) {
rv.setTextViewText(R.id.TextView01, context.getResources()
.getString(R.string.load));
} else {
rv.setTextViewText(R.id.TextView01, context.getResources()
.getString(R.string.change));
}
Toast.makeText(context, Boolean.toString(uitil.isChange),
Toast.LENGTH_LONG).show();
uitil.isChange = !uitil.isChange;
}
AppWidgetManager appWidgetManger = AppWidgetManager
.getInstance(context);
int[] appIds = appWidgetManger.getAppWidgetIds(new ComponentName(
context, widgetProvider.class));
appWidgetManger.updateAppWidget(appIds, rv);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
在onReceiver中通过判断传进来的广播来触发动作。
5、如何使TextView在两种文本间来回跳转
如何TextView在来两种状态中来回呢?这也是我比较调试最久的一个难点,问题出在对AppWidget的理解不够深入。如果我的设想没错的话AppWidget的生命周期应该在每接收一次广播执行一次为一个生命周期结束,也就是说你在重写的AppWidgetProvider类里面声明全局变量做状态判断,每次状态改变AppWidgetProvider再接收第二次广播时即为你重新初始化也就是说桌件为你重新实例化了一次AppWidgetProvider。今天我因为在里面放了一个boolean值初始化为true,观察调试看到每次进入都为TRUE故你在设置桌面组件时,全局变量把它声明在另外一个实体类用来判断是没问题的,切忌放在本类。代码参考onReceiver方法。
效果图如下:

代码:
代码
package com.terry;
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.widget.RemoteViews;
import android.widget.Toast;
public class widgetProvider extends AppWidgetProvider {
private static final String CLICK_NAME_ACTION = "com.terry.action.widget.click";
private static RemoteViews rv;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// TODO Auto-generated method stub
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
super.onReceive(context, intent);
if (rv == null) {
rv = new RemoteViews(context.getPackageName(), R.layout.main);
}
if (intent.getAction().equals(CLICK_NAME_ACTION)) {
if (uitil.isChange) {
rv.setTextViewText(R.id.TextView01, context.getResources()
.getString(R.string.load));
} else {
rv.setTextViewText(R.id.TextView01, context.getResources()
.getString(R.string.change));
}
Toast.makeText(context, Boolean.toString(uitil.isChange),
Toast.LENGTH_LONG).show();
uitil.isChange = !uitil.isChange;
}
AppWidgetManager appWidgetManger = AppWidgetManager
.getInstance(context);
int[] appIds = appWidgetManger.getAppWidgetIds(new ComponentName(
context, widgetProvider.class));
appWidgetManger.updateAppWidget(appIds, rv);
}
public static void updateAppWidget(Context context,
AppWidgetManager appWidgeManger, int appWidgetId) {
rv = new RemoteViews(context.getPackageName(), R.layout.main);
Intent intentClick = new Intent(CLICK_NAME_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
intentClick, 0);
rv.setOnClickPendingIntent(R.id.TextView01, pendingIntent);
appWidgeManger.updateAppWidget(appWidgetId, rv);
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
小结:Android桌面组件widget初探的内容介绍完了,希望通过Android Widget 的应用内容的学习能对你有所帮助!