Android桌面小部件AppWidget的使用,本例假设实现一个简单的功能,窗口小部件有一个Android Button和TextView,当点击桌面小部件时候,把系统当前的毫秒事件显示在TextView里面。

(1)首先需要在Androidmanifest.xml文件代码定义窗口小部件(类似广播的静态注册):

 <receiver android:name=".AppWidget" > 
            <intent-filter> 
                <action android:name="action_button" /> 
            </intent-filter> 
             
            <intent-filter> 
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> 
            </intent-filter> 
 
            <meta-data 
                android:name="android.appwidget.provider" 
                android:resource="@xml/appwidget" /> 
        </receiver>

其中需要在res/xml目录下新建一个appwidget.xml代码文件定义appwidget-provider相关属性:

<?xml version="1.0" encoding="utf-8"?> 
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 
    android:initialLayout="@layout/appwidget_layout" 
    android:minHeight="20dip" 
    android:minWidth="200dip" 
    android:previewImage="@drawable/ic_launcher" 
    android:resizeMode="horizontal|vertical" 
    android:updatePeriodMillis="0" 
    android:widgetCategory="home_screen" > 
 
</appwidget-provider>



之所以同时定义了:


 <intent-filter> 
                <action android:name="action_button" /> 
            </intent-filter>


是因为在我写的这个例子中,将有Button触发事件,但Android窗口小部件机制不像普通Android activity一样直接在类似Button的onClick的方法内处理业务逻辑,而是通过广播出去一个事件,然后又接受者通过RemoteViews处理。


(2)自己写一个类继承自AppWidgetProvider(核心关键):


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.util.Log; 
import android.widget.RemoteViews; 
 
public class AppWidget extends AppWidgetProvider { 
 
	private final String ACTION_BUTTON = "action_button"; 
 
	/** 
	 * 接受广播事件 
	 */ 
	@Override 
	public void onReceive(Context context, Intent intent) { 
		super.onReceive(context, intent); 
		Log.d(this.getClass().getName(), "onReceive"); 
		 
		if (intent == null) 
			return; 
 
		String action = intent.getAction(); 
 
		if (action.equals(ACTION_BUTTON)) { 
			// 只能通过远程对象来设置appWidget中的状态 
			RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout); 
			remoteViews.setTextViewText(R.id.text, ""+System.currentTimeMillis()); 
 
			AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); 
 
			ComponentName componentName = new ComponentName(context, AppWidget.class); 
 
			// 更新appWidget 
			appWidgetManager.updateAppWidget(componentName, remoteViews); 
		} 
	} 
 
	/** 
	 * 到达指定的更新时间或者当用户向桌面添加AppWidget时被调用 
	 * appWidgetIds:桌面上所有的widget都会被分配一个唯一的ID标识,这个数组就是他们的列表 
	 */ 
	@Override 
	public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 
		Log.d(this.getClass().getName(), "onUpdate"); 
		 
		Intent intent = new Intent(ACTION_BUTTON); 
		PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0); 
 
		// 小部件在Launcher桌面的布局 
		RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout); 
 
		// 事件 
		remoteViews.setOnClickPendingIntent(R.id.btn, pendingIntent); 
 
		// 更新AppWidget 
		appWidgetManager.updateAppWidget(appWidgetIds, remoteViews); 
	} 
	 
	 
	/** 
	 * 删除AppWidget 
	 */ 
	@Override 
	public void onDeleted(Context context, int[] appWidgetIds) { 
		super.onDeleted(context, appWidgetIds); 
		Log.d(this.getClass().getName(), "onDeleted"); 
	} 
 
	@Override 
	public void onDisabled(Context context) { 
		super.onDisabled(context); 
		Log.d(this.getClass().getName(), "onDisabled"); 
	} 
 
	/** 
	 * AppWidget首次创建调用 
	 */ 
	@Override 
	public void onEnabled(Context context) { 
		super.onEnabled(context); 
		Log.d(this.getClass().getName(), "onEnabled"); 
	} 
}



Android的桌面小部件从继承AppWidgetProvider开始,以我写的代码为例,我创建了一个Android窗口小部件名字叫AppWidget。AppWidgetProvider本身从一定角度上讲是一个Android的广播。
一般的,重写AppWidget里面的onReceive方法,用以后面的更新操作。
AppWidget的onUpdate里面完成view事件的初始化操作,在AppWidget里面,由于窗口小部件与本地代码运行在不同的进程空间,所以只能通过RemoteViews处理与相关view绑定的事件响应。
本例的RemoteViews需要的布局文件在res/layout下的appwidget_layout.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="wrap_content" 
    android:orientation="horizontal" 
    android:background="#33000000" > 
 
    <Button 
        android:id="@+id/btn" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="按钮" > 
    </Button> 
    
    <TextView 
        android:id="@+id/text" 
        android:text="text" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" /> 
 
</LinearLayout>


RemoteViews将基于appwidget_layout.xml负责在桌面窗口小部件的外观。

在onUpdate里面完成view与事件的绑定后,以本文为例,那么之后对按钮button的按击所产生的事件将会被传递广播到AppWidget的onReceive里面。AppWidget的交互设计模型是在onUpdate里面通过RemoteViews把view通过与事件绑定在一起,然后之后的事件触发及操作,是在onUpdate里面通过广播的形式广播出去一个Intent,此广播将有AppWidget的onReceive接收处理,在AppWidget的onReceive里面更新桌面小部件的UI等等。即:
onUpdate -> onReceive ,此过程基于广播机制。


代码运行结果如图:


发布评论

分享到:

IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Android桌面小部件AppWidget(2)详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。