RemoteViews用法二:可以接收點選事件並改變外觀的widget
阿新 • • 發佈:2019-02-02
這篇部落格完成一個可以接收點選事件並改變外觀的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的特殊性,所以設定的程式碼和平時設定監聽的程式碼有點區別,而且能設定的事件監聽型別也比較有限,具體區別參考