首页 > 代码库 > Android Widget 小部件(一) 简单实现

Android Widget 小部件(一) 简单实现

在屏幕上添加Widget:或长按屏幕空白处,或找到WidgetPreview App选择。原生系统4.0以下使用长按方式,4.0及以上 打开WIDGETS

创建Widget的一般步骤:
在menifest中

<receiver android:name="com.stone.ui.TimerWidgetProvider">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
                 <!-- 自定义action -->
                 <action android:name="com.stone.action.start"/>
             </intent-filter>
             <meta-data android:name="android.appwidget.provider"
                 android:resource="@xml/timer_widget_provider"/>
                 <!--  android:resource="" 定义了Widget的信息使用timer_widget_provider.xml描述 -->
</receiver>

Widget描述文件:timer_widget_provider.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="180dp"
    android:minHeight="40dp"
    android:updatePeriodMillis="5000"
    android:previewImage="@drawable/ic_launcher"
    android:initialLayout="@layout/timer_widget"
    android:resizeMode="horizontal|vertical" >
	<!-- 
		计算size的公式: (70*n) -30  n为部件所需的大小(占几格)   当前的就是  3X1
		minResizeWidth
    	minResizeHeight   能被调整的最小宽高,若大于minWidth minHeight 则忽略
    	label	选择部件时看到标签
    	icon	选择部件时看到图标
    	updatePeriodMillis	更新时间间隔
    	previewImage	选择部件时 展示的图像  3.0以上使用
    	initialLayout	布局文件
    	resizeMode		调整size模式
    	configure		如果需要在启动前先启动一个Activity进行设置,在这里给出Activity的完整类名
    	autoAdvanceViewId=@id/xx	与集合部件一起使用,指定应该通过部件的host自动提前的视图ID
    	
    	集合部件:3.0后才有。view:ListView、GridView、StackView、AdapterViewFilpper
	 -->
</appwidget-provider>

Widget使用的布局:timer_widget.xml
<?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="horizontal"
    android:background="@drawable/widget_background" >
    
	<TextView 
	    android:id="@+id/counter"
	    android:layout_width="0dp"
	    android:layout_height="match_parent"
	    android:layout_weight="1"
	    android:gravity="center"
	    android:text="00:00"
	    android:singleLine="true"
	    android:textAppearance="?android:attr/textAppearance"/>
	<ImageView
	    android:id="@+id/start_stop"
	    android:layout_width="0dp"
	    android:layout_height="match_parent"
	    android:layout_weight="1"
	    android:scaleType="center"
	    android:src=http://www.mamicode.com/"@android:drawable/ic_media_play"/>>
处理Widget相关事件的 AppWidgetProvider
package com.stone.ui;

import java.util.Arrays;

import com.stone.R;
import com.stone.service.TimerWidgetService;

import android.app.PendingIntent;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.text.format.DateUtils;
import android.widget.RemoteViews;

/*
 * AppWidgetProvider 必须要接收android.appwidget.action.APPWIDGET_UPDATE 广播
 * 
 */
public class TimerWidgetProvider extends AppWidgetProvider {
	
	@Override //更新部件时调用,在第1次添加部件时也会调用
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {
		super.onUpdate(context, appWidgetManager, appWidgetIds);
		System.out.println("onUpdate widget:" + Arrays.toString(appWidgetIds));
		/*
		 * 构造pendingIntent发广播,onReceive()根据收到的广播,更新
		 */
		Intent intent = new Intent(context, TimerWidgetService.class);
		PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
		RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.timer_widget);
		rv.setOnClickPendingIntent(R.id.start_stop, pendingIntent);
		appWidgetManager.updateAppWidget(appWidgetIds, rv);
	}
	
	@Override	//部件从host中删除
	public void onDeleted(Context context, int[] appWidgetIds) {
		super.onDeleted(context, appWidgetIds);
		System.out.println("onDeleted widget");
	}
	
	@Override //第1次创建时调用,之后再创建不会调用
	public void onEnabled(Context context) {
		super.onEnabled(context);
		System.out.println("onEnabled widget");
	}
	
	@Override //当最后一个部件实例 被删除时 调用  用于清除onEnabled执行的操作
	public void onDisabled(Context context) {
		super.onDisabled(context);
		System.out.println("onDisabled widget");
	}
	
	@Override //
	public void onReceive(Context context, Intent intent) {
		super.onReceive(context, intent);
		System.out.println("onReceive widget");
		/*
		 * 接收 <action android:name="com.stone.action.start"/>
           在其他组件或activity或service中发送这些广播
           
		 */
		if (intent.getAction().equals("com.stone.action.start")) {
			long time = intent.getLongExtra("time", 0);
			 updateWidget(context, time);
			 System.out.println("receive com.stone.action.start");
		}
	}
	
	private void updateWidget(Context context, long time) {
		//RemoteViews处理异进程中的View
		RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.timer_widget);
		System.out.println("time=" + time);
		rv.setTextViewText(R.id.counter, DateUtils.formatElapsedTime(time / 1000));
		
		AppWidgetManager am = AppWidgetManager.getInstance(context);
		int[] appWidgetIds = am.getAppWidgetIds(new ComponentName(context, TimerWidgetProvider.class));
		am.updateAppWidget(appWidgetIds, rv);//更新 所有实例
	}
}

AppWidgetProvider中使用的TimerWidgetService

package com.stone.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class TimerWidgetService extends Service {

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		/*
		 * do some thing
		 */
		//发送广播通知 widget 更新 状态
		sendBroadcast(new Intent("com.stone.action.start").putExtra("time", System.currentTimeMillis()));
		return Service.START_STICKY;
	}
}