Android桌面小组件Widget开发入门 AppWidgetProvider的使用

2011.05.23 更新:
经过半天的测试,确定1.6以上版本Widget更新时间为半小,但是添加Widget后第一次启动有延迟,是37分左右,后面每次更新都是间隔30分钟。

想必大家都用过桌面小组件,像天气预报,时钟之类的,与Activity不同,它的主体是一个显示在桌面上可移动的视图,而并不是一个独立的程序。
先看例子的效果图:

不太好看,但是没关系,UI不是重点,重点是怎么把它写出来。
解释一下,一个红色的界面,上面有个TextView,显示一个数字,这个数字每秒加1,点击数字会跳出一个Activity.OK,下面来实现。
先介绍下结构:
Main.java 主程序,一个Activity,点击桌面的Widget上文字后跳出,也可以在程序列表上点图标启动。
UpdateService.java 一个更新桌面Widget的服务Service,每隔一秒更新视图
Widget.java 这个才是桌面Widget需要用到的程序,继承自AppWidgetProvider
layout/main.xml Main Activity和Widget用到的布局文件,Activity和Widget都用这个作而已(简单起见)
xml/widget.xml Widget的配置文件,配置显示的宽、高,更新时间,指定布局文件(main.xml)
下面贴代码:
先是AndroidManifest.xml:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.pocketdigi.widget" android:versionCode="1"
	android:versionName="1.0">
	<application android:icon="@drawable/icon" android:label="@string/app_name">
		<receiver android:label="@string/app_name" android:name=".Widget">
			<intent-filter>
				<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
			</intent-filter>
			<meta-data android:resource="@xml/widget" android:name="android.appwidget.provider" />
		</receiver>
		<activity android:name=".Main">
			<intent-filter>
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
		<service android:name=".UpdateService" />
	</application>
</manifest>


AppWidgetProvider类继承于BroadcastReceiver,所以这里定义的时候跟BroadcastReceiver是一样的,用receiver标签
android.appwidget.action.APPWIDGET_UPDATE是固定值,在添加widget到桌面时会发送该广播
android.appwidget.provider设置的是AppWidgetProvider配置的XML文件
再下面是一个actvity,一个service,不再解释

Main.java就不贴了,在这里就是自动生成的Hello World
Widget.java:


package com.pocketdigi.widget;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;

public class Widget extends AppWidgetProvider {

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {
		// TODO Auto-generated method stub
		//添加到桌面和更新界面时执行,但是1.6以后没有了updatePeriodMillis属性,所以会看不到更新界面执行的效果
		System.out.println("onUpdate");
		Intent intent=new Intent(context,UpdateService.class);
		context.startService(intent);
		//启动服务
		super.onUpdate(context, appWidgetManager, appWidgetIds);
	}

	@Override
	public void onDeleted(Context context, int[] appWidgetIds) {
		// TODO Auto-generated method stub
		//被删除时执行
		System.out.println("删除");
		Intent intent=new Intent(context,UpdateService.class);
		context.stopService(intent);
		//停止后台服务
		super.onDeleted(context, appWidgetIds);
	}
	
}

UpdateService.java;


package com.pocketdigi.widget;

import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Intent;
import android.os.IBinder;
import android.widget.RemoteViews;

public class UpdateService extends Service {
	boolean is_run = false;
	boolean flag=true;
	//标记线程是否已经启动,已启动就不会再次启动
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onStart(Intent intent, int startId) {
		// TODO Auto-generated method stub
		super.onStart(intent, startId);
		final RemoteViews updateViews = new RemoteViews(this.getPackageName(),
				R.layout.main);
		final ComponentName thisWidget = new ComponentName(this, Widget.class);
		final AppWidgetManager manager = AppWidgetManager.getInstance(this);

		if (!is_run) {
			//如果已经启动,不执行
			new Thread() {
				//因为XML中的updatePeriodMillis属性无效,为了测试更新界面的效果
				// 所以,我在这新建了一个线程,在里面无限循环更新APP Widget
				//第一天学这个,不知道这样会不会很费电,不知道还有什么其他方法,以后如果发现再补充
				public void run() {
					int i = 0;
					is_run=true;
					while (flag) {
						updateViews.setTextViewText(R.id.tv, String.valueOf(i));
						updateViews.setInt(R.id.tv, "setTextColor",
								R.color.black);
						updateViews.setFloat(R.id.tv, "setTextSize", 20.0f);
						// setXX方法,三个参数分别为操作控件在XML中的ID,
						// 执行的方法名(该控件ID通过findViewById得到的view,该view的方法,上面执行的就是TextView的setTextColor和setTextSize方法)
						// 方法的参数,setXX需要根据该参数类型确定,如setTextColor的参数是int,就调用setInt,setTextSize的参数是Float,就调用setFloat
						Intent intent = new Intent(UpdateService.this,
								Main.class);
						PendingIntent pendingintent = PendingIntent
								.getActivity(UpdateService.this, 0, intent, 0);
						updateViews.setOnClickPendingIntent(R.id.tv,
								pendingintent);
						// 以上几行相当于调用TextView的setOnClickListener方法,在点击时启动Main这个Activity
						manager.updateAppWidget(thisWidget, updateViews);
						// 更新
						i++;
						try {
							sleep(1000);
							// 休息1秒
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}.start();
		}

	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		System.out.println("onDestory");
		flag=false;
		//服务停止时停止线程
		super.onDestroy();
	}


}

Main.xml,其实就是把自动生成的Hello World的TextView加个ID:


<?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="@color/red"
    >
<TextView  android:id="@+id/tv"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
</LinearLayout>

widget.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="5000"
  android:initialLayout="@layout/main"
  >
</appwidget-provider>

前两个分别是宽,高的最小值,我在测试的时候,没发现修改这两个值对Widget显示的宽高有什么影响,希望知道的同学留下言
updatePeriodMillis更新间隔时间,单位毫秒,根据实际测试,以及网上的资料,如果android版本在1.6及以上,不支持这个属性,好像默认半小时左右更新
最后是Widget小组件的界面xml文件
另外,在strings.xml中加了两个颜色值:


    <color name="red">#ff0000</color>
    <color name="black">#000000</color>

OK,就是这样,测试一下吧!附上打包的源代码,为了提高人气,回得可见,望理解:
抱歉,只有对本站任何文章发表过评论才能阅读隐藏内容。

© 2011, 冰冻鱼. 请尊重作者劳动成果,复制转载保留本站链接! 应用开发笔记