1. 程式人生 > >RemoteViews用法二:可以接收點選事件並改變外觀的widget

RemoteViews用法二:可以接收點選事件並改變外觀的widget

這篇部落格完成一個可以接收點選事件並改變外觀的widget,並簡要總結,最後附上原始碼下載地址。

Demo程式碼:

1.定義Widget佈局XML                     /res/layout/widget_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/widget_start"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="start" />
    <Button
        android:id="@+id/widget_stop"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="stop" />

    <TextView
        android:id="@+id/widget_text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="text"
        android:textColor="#fff" />

</LinearLayout>

2.定義Widget屬性檔案         /res/xml/widget_info.xml  這裡不附程式碼

3. 建立FirstWidgetProvider子類,實現onUpdate()等函式。

package net.qingtian.appwidget2;

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;

/**
 * AppWidgetProvider子類
 * @author qingtian 2014年11月21日15:02:53
 */
public class FirstWidgetProvider extends AppWidgetProvider {

	private static final String TAG = "qingtian";
	// 定義一個常量字串,該常量用於命名Action
	private static final String UPDATA_STATUS_FROM_WIDGET_START = "net.qingtian.UPDATA_STATUS_FROM_WIDGET_START";
	private static final String UPDATA_STATUS_FROM_WIDGET_STOP = "net.qingtian.UPDATA_STATUS_FROM_WIDGET_STOP";

	@Override
	public void onReceive(Context context, Intent intent) {
		Log.i(TAG, "onReceive");

		String action = intent.getAction();
		if (UPDATA_STATUS_FROM_WIDGET_START.equals(action)) {
			// 改變widget外觀
			setViewStatus(context, 1);
		} else if (UPDATA_STATUS_FROM_WIDGET_STOP.equals(action)) {
			// 改變widget外觀
			setViewStatus(context, 0);
		} else {
			super.onReceive(context, intent);// 這裡一定要新增,eles部分,不然,onReceive不會去呼叫其它的方法。但是如果把這條語句放在外面,就會每次執行onUpdate,onDeleted等方法,就會執行兩次,因為UPDATE_ACTION.equals(action)配置成功會執行一次,super.onReceive(context,
												// intent)配置成功又會執行一次,後都是系統自定義的。
		}
	}

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {
		Log.i(TAG, "onupdated");

		RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
				R.layout.widget_layout);

		// 設定開始監聽
		Intent intentStart = new Intent();
		// 為Intent物件設定Action
		intentStart.setAction(UPDATA_STATUS_FROM_WIDGET_START);
		// 使用getBroadcast方法,得到一個PendingIntent物件,當該物件執行時,會發送一個廣播
		PendingIntent pendingIntentStart = PendingIntent.getBroadcast(context,
				0, intentStart, 0);
		remoteViews.setOnClickPendingIntent(R.id.widget_start,
				pendingIntentStart);

		// 設定停止監聽
		Intent intentStop = new Intent();
		// 為Intent物件設定Action
		intentStop.setAction(UPDATA_STATUS_FROM_WIDGET_STOP);
		// 使用getBroadcast方法,得到一個PendingIntent物件,當該物件執行時,會發送一個廣播
		PendingIntent pendingIntentStop = PendingIntent.getBroadcast(context,
				0, intentStop, 0);
		remoteViews
				.setOnClickPendingIntent(R.id.widget_stop, pendingIntentStop);

		appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
		super.onUpdate(context, appWidgetManager, appWidgetIds);
	}

	@Override
	public void onDeleted(Context context, int[] appWidgetIds) {
		Log.i(TAG, "onDeleted");
		super.onDeleted(context, appWidgetIds);
	}

	@Override
	public void onDisabled(Context context) {
		Log.i(TAG, "onDisabled");
		super.onDisabled(context);
	}

	@Override
	public void onEnabled(Context context) {
		Log.i(TAG, "onEnabled");
		super.onEnabled(context);
	}

	/**
	 * 設定widget的狀態,即改變textView裡面的文字
	 * 
	 * @param status
	 */
	public void setViewStatus(Context context, int status) {
		RemoteViews remoteViews = null;
		if (status == 0) {// 結束
			remoteViews = new RemoteViews(context.getPackageName(),
					R.layout.widget_layout);
			remoteViews.setTextViewText(R.id.widget_text, "0       結束");
		} else if (status == 1) {// 開始
			remoteViews = new RemoteViews(context.getPackageName(),
					R.layout.widget_layout);
			remoteViews.setTextViewText(R.id.widget_text, "1      開始");
		} else {
			return;
		}
		// remoteViews.setTextViewText(R.id.test_text, "data  "+data);
		// getInstance(Context context) Get the AppWidgetManager instance to
		// use for the supplied Context object.靜態方法。
		AppWidgetManager appWidgetManager = AppWidgetManager
				.getInstance(context);
		ComponentName componentName = new ComponentName(context,
				FirstWidgetProvider.class);
		appWidgetManager.updateAppWidget(componentName, remoteViews);
	}

}

4.在manifest中註冊receiver,新增一個action為 android.appwidget.action.APPWIDGET_UPDATE 的IntentFilter,並新增如下<meta- data>標識:

<receiver
            android:name="net.qingtian.appwidget2.FirstWidgetProvider"
            android:label="wid2" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="net.qingtian.UPDATA_STATUS_FROM_WIDGET_START" />
                <action android:name="net.qingtian.UPDATA_STATUS_FROM_WIDGET_STOP" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widget_info" >
            </meta-data>
 </receiver>

總結:

1.關於事件處理的大體流程:由於widget和原來的程式是相對獨立的,所以它的事件監聽也有些與眾不同,主要就是廣播的來傳遞訊息。大體分為兩步:a.設定widget裡的元件被點選後傳送廣播。b.我們寫的AppWidgetProvider的子類可以接收這些廣播,然後響應事件,比如改變widget外觀,改變service的狀態等。

2.關於設定widget裡的元件的onclick事件監聽:通過widget的生命週期來看,初始化widget裡元件的事件監聽放在onUpdate方法裡。步驟為:構造RemoteViews->為RemoteViews裡的元件設定onClick事件->把RemoteViews與widget關聯。在這個demo裡,我為元件新增的事件監聽處理是傳送廣播。

3.關於接收這些廣播,首先AppWidgetProvider就是繼承自BroadcastReceiver,只是它預設處理了一些和widget的廣播,我們需要去重寫onRecevie,但是要保證不能影響他處理預設的廣播的功能。

4.在給widget裡的元件設定監聽時,用到RemoteViews,由於RemoteViews的特殊性,所以設定的程式碼和平時設定監聽的程式碼有點區別,而且能設定的事件監聽型別也比較有限,具體區別參考

原始碼下載: