android桌面组件AppWidget
====================================================
http://blog.csdn.net/meshless/article/details/6941499
===================================================
前几天学习下了桌面组件开发,现将学习心得跟大家交流下,欢迎探讨!
一、 概述
要进行桌面组件Widget开发,首先要了解AppWidget框架结构。AppWidget是Android 1.5平台推出的一种崭新的应用程序框架。基于AppWidget框架,开发人员可以在OPhone及模拟器上开发形似传统widget的小应用程序,并将其嵌入到其他应用中。
二、 AppWidet框架
1、AppWidgetProvider :继承自 BroadcastRecevier , 在AppWidget 应用 update、enable、disable 和 delete 时接收通知。其中,onUpdate、onReceive 是最常用到的方法,它们接收更新通知。 下面对AppWidgetProvider类常用到的方法进行介绍:
(1)onDeleted(Context context, int[]appWidgetIds)
(2)onDisabled(Context context)
(3)onEnabled(Context context)
(4)onReceive(Context context, Intentintent)
Tip:因为 AppWidgetProvider 是继承自BroadcastReceiver 所以可以重写onRecevie 方法,当然必须在后台注册Receiver
(5)onUpdate(Context context,AppWidgetManager appWidgetManager, int[] appWidgetIds)
2、 AppWidgetProvderInfo:描述 AppWidget 的大小、更新频率和初始界面等信息,以XML 文件形式存在于应用的res/xml/目录下。
3、AppWidgetManger :负责管理 AppWidget ,向 AppwidgetProvider 发送通知。 下面对AppWidgetManger 类中主要方法进行介绍:
(1)bindAppWidgetId(int appWidgetId,ComponentName provider)
通过给定的ComponentName 绑定appWidgetId
(2)getAppWidgetIds(ComponentNameprovider)
通过给定的ComponentName 获取AppWidgetId
(3)getAppWidgetInfo(int appWidgetId)
通过AppWidgetId 获取 AppWidget 信息
(4)getInstalledProviders()
返回一个List<AppWidgetProviderInfo>的信息
(5)getInstance(Context context)
获取 AppWidgetManger 实例使用的上下文对象
(6)updateAppWidget(int[] appWidgetIds,RemoteViews views)
通过appWidgetId 对传进来的 RemoteView 进行修改,并重新刷新AppWidget 组件
(7)updateAppWidget(ComponentNameprovider, RemoteViews views)
通过 ComponentName 对传进来的 RemoeteView 进行修改,并重新刷新AppWidget 组件
(8)updateAppWidget(int appWidgetId,RemoteViews views)
通过appWidgetId 对传进来的 RemoteView 进行修改,并重新刷新AppWidget 组件
4、RemoteViews :一个可以在其他应用进程中运行的类,向 AppWidgetProvider 发送通知。这是构造AppWidet的核心。
三、 Widget 示例:WidgetDemo
下面改写一个倒计时Demo,该Widget背景图能定时更新。
先看下程序运行效果图:
1、 新建一个Android工程,命名为WidgetDemo
2、 修改string.xml文件如下:
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string name="hello">Hello World, WidgetDemo!</string>
- <string name="app_name">DaysToMay1ST</string>
- </resources>
3、 修改main.xml布局文件。
由于Widget是一个实现在桌面的小应用程序,对UI的设计要求高,其中包括大小的计算和界面是否适合屏幕的布局等。所以首先要建立RemoteViews对应的布局文件main.xml。
代码如下:
- <?xml version="1.0"encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/sunset"
- >
- <TextView
- android:id="@+id/may1st"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/hello"
- android:textSize="12px"
- android:textColor="#ff0000"
- />
- </LinearLayout>
4、 建立Widget内容提供者文件。我们在res下建立xml文件夹,并且新建一个widget_provider.xml代码如下:
- <?xml version="1.0"encoding="utf-8"?>
- <appwidget-provider
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:minWidth="50dip"
- android:minHeight="50dip"
- android:updatePeriodMillis="10000"
- android:initialLayout="@layout/main"
- >
- </appwidget-provider>
- package com.android.rui;
- import java.util.Calendar;
- import java.util.Date;
- import java.util.GregorianCalendar;
- import java.util.Timer;
- import java.util.TimerTask;
- import android.appwidget.AppWidgetManager;
- import android.appwidget.AppWidgetProvider;
- import android.content.ComponentName;
- import android.content.Context;
- import android.widget.RemoteViews;
- public class WidgetDemo extends AppWidgetProvider {
- /** Called when the activityis first created. */
- @Override
- public void onUpdate(Context context, AppWidgetManagerappWidgetManager,
- int[] appWidgetIds){
- Timer timer = new Timer();
- timer.scheduleAtFixedRate(new MyTime(context,appWidgetManager), 1, 60000);
- super.onUpdate(context,appWidgetManager, appWidgetIds);
- }
- private class MyTime extends TimerTask{
- RemoteViews remoteViews;
- AppWidgetManager appWidgetManager;
- ComponentName thisWidget;
- public MyTime(Contextcontext,AppWidgetManager appWidgetManager){
- this.appWidgetManager =appWidgetManager;
- switch(Declare.i)//让widget背景图定时变换
- {
- case 1:
- remoteViews = new RemoteViews(context.getPackageName(),R.layout.main1);
- Declare.i++;
- break;
- case 2:
- remoteViews = new RemoteViews(context.getPackageName(),R.layout.main2);
- Declare.i++;
- break;
- case 3:
- remoteViews = new RemoteViews(context.getPackageName(),R.layout.main3);
- Declare.i++;
- break;
- default:
- remoteViews = new RemoteViews(context.getPackageName(),R.layout.main);
- Declare.i=0;
- Declare.i++;
- break;
- }
- thisWidget = newComponentName(context,WidgetDemo.class);
- }
- public void run() {
- Date date = new Date();
- Calendarcalendar = new GregorianCalendar(2011,05,01);
- long days =(((calendar.getTimeInMillis()-date.getTime())/1000))/86400-30;
- remoteViews.setTextViewText(R.id.may1st, "距离五一假期还有" + days+"天");
- appWidgetManager.updateAppWidget(thisWidget, remoteViews);
- }
- }
- }
由于使用了reciever和“android.appwidget.action.APPWIDGET_UPDATE”,所以需要在AndroidManifest.xml中进行注册。
代码如下:
- <?xml version="1.0"encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.rui"
- android:versionCode="1"
- android:versionName="1.0">
- <application android:icon="@drawable/icon"android:label="@string/app_name">
- <receiver android:name=".WidgetDemo"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
- </intent-filter>
- <meta-data android:name="android.appwidget.provider"
- android:resource="@xml/widget_provider"
- />
- </receiver>
四、 Widget事件处理
在以上五一假期倒计时的DEMO中只是更新显示了一个界面。在Widget中同样可以通过setOnClickPendingIntent方法来监听一个事件的处理。
比如:当我们点击一个”widget_button”按钮时,会弹出一个Toast提示。主要代码如下:
- public class widget extends AppWidgetProvider
- {
- public void onReceive(Context context,Intent intent)
- {
- super.onReceive(context,intent);
- if(intent.getAction().equals("com.android.myapp.widget.CLICK"))
- {
- Toast.makeText(context,"It works!",Toast.LENGTH_SHORT).show();
- }
- }
- public void onUpdate(Context context, AppWidgetManagerappWidgetManager,int[] appWidgetIds) {
- final int N = appWidgetIds.length;
- for (int i = 0; i < N; i++) {
- int appWidgetId = appWidgetIds[i];
- RemotesViews rv = new RemoteViews(context.getPackageName(),R.layout.main);
- Intent intentClick = new Intent("com.android.myapp.widget.CLICK");
- PendingIntent pendingIntent =PendingIntent.getBroadcast(context, 0,intentClick, 0);
- rv.setOnClickPendingIntent(R.id.widget_button,pendingIntent);
- appWidgetManager.updateAppWidget(appWidgetId, rv);
- }
- }
- }
五、 Widget启动Activity
在Widget中同样可以启动一个Activity,比如Android自带的音乐播放器,当我们添加一个音乐播放器桌面小部件并点击”button”时就开启一个Activity来显示播放音乐的界面。
通过如下代码即可以启动一个Activity:
- RemoteViews rv=newRemoteViews(context.getPackageName(),R.layout.mywidget);
- Intent intentActivity=new Intent(context,MusicPlayer.class);
- PendingIntentpendingIntentActivity=PendingIntent.getActivity(context, 0, intentActivity, 0);
- rv.setOnClickPendingIntent(R.id.button,pendingIntentActivity);
- appWidgetManager.updateAppWidget(appWidgetId,rv);
- context.startActivity(intentActivity);
六、 Widget启动Service
Widget还可以启动一个服务。比如Android自带的音乐播放器,要播放音乐肯定需要使用service在后台播放,所以就需要在音乐播放器桌面小部件中启动一个service。使用下面方法可以在Widget中启动一个Service:
- RemoteViews rv=new RemoteViews(context.getPackageName(),R.layout.mywidget);
- Intent intentService=new Intent(“Service名”);
- context.startService(intentService);
- appWidgetManager.updateAppWidget(appWidgetId,rv);