setRemoteAdapter (int viewId, Intent intent):該方法能夠使用 Intent 更新 RemoteViews 中viewId 對應的組件。
java
上面方法的 Intent 參數應該封裝一個 RemoteViewsService 參數,RemoteViewsService 雖然繼承了 Service 組件,但它的主要做用是爲 RemoteViews 中 viewId 對應的組件提供列表項。android
因爲Intent參數負責提供列表項,所以viewId參數對應的組件能夠是ListView、GridView、StackView 和 AdapterViewFlipper 等,這些組件都是 AdapterView 的子類,因而可知RemoteViewsService 負責提供的對象,應該是一個相似於 Adapter 的對象。數組
RemoteViewsService 一般用於被繼承,繼承該基類時須要重寫它的 onGetViewFactory()方 法 , 該 方 法 就 需 要 返 回 一 個 類 似 於 Adapterr 對 象 —— 但 不 是 Adapter , 而 是RemoteViewsFactory 對象,RemoteViewsFactory 的功能徹底相似於 Adapter。app
StackViewWidget實現以下:ide
StackWidgetService.javaoop
package org.crazyit.desktop; import android.content.Context; import android.content.Intent; import android.widget.RemoteViews; import android.widget.RemoteViewsService; /** * Description: * <br/>網站: <a href="http://www.crazyit.org">瘋狂Java聯盟</a> * <br/>Copyright (C), 2001-2014, Yeeku.H.Lee * <br/>This program is protected by copyright laws. * <br/>Program Name: * <br/>Date: * @author Yeeku.H.Lee kongyeeku@163.com * @version 1.0 */ public class StackWidgetService extends RemoteViewsService { // 重寫該方法,該方法返回一個RemoteViewsFactory對象。 // RemoteViewsFactory對象的的做用相似於Adapter, // 它負責爲RemoteView中指定組件提供多個列表項。 @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new StackRemoteViewsFactory(this.getApplicationContext(), intent); //① } class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { // 定義一個數組來保存該組件生成的多個列表項 private int[] items = null; private Context mContext; public StackRemoteViewsFactory(Context context, Intent intent) { mContext = context; } @Override public void onCreate() { // 初始化items數組 items = new int[] { R.drawable.bomb5, R.drawable.bomb6, R.drawable.bomb7, R.drawable.bomb8, R.drawable.bomb9, R.drawable.bomb10, R.drawable.bomb11, R.drawable.bomb12, R.drawable.bomb13, R.drawable.bomb14, R.drawable.bomb15, R.drawable.bomb16 }; } @Override public void onDestroy() { items = null; } // 該方法的返回值控制該對象包含多少個列表項 @Override public int getCount() { return items.length; } // 該方法的返回值控制各位置所顯示的RemoteViews @Override public RemoteViews getViewAt(int position) { // 建立RemoteViews對象,加載/res/layout目錄下widget_item.xml文件 RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item); // 更新widget_item.xml佈局文件中的widget_item組件 rv.setImageViewResource(R.id.widget_item, items[position]); // 建立Intent、用於傳遞數據 Intent fillInIntent = new Intent(); fillInIntent.putExtra(StackWidgetProvider.EXTRA_ITEM, position); // 設置當單擊該RemoteViews時傳遞fillInIntent包含的數據 rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent); // 此處使用讓線程暫停0.5秒來模擬加載該組件 try { System.out.println("加載【" + position + "】位置的組件"); Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } return rv; } @Override public RemoteViews getLoadingView() { return null; } @Override public int getViewTypeCount() { return 1; } @Override public long getItemId(int position) { return position; } @Override public boolean hasStableIds() { return true; } @Override public void onDataSetChanged() { } } }
widget_item.xml佈局
<?xml version="1.0" encoding="utf-8"?> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/widget_item" android:layout_width="120dp" android:layout_height="120dp" android:gravity="center"/>
StackWidgetProvider.java網站
package org.crazyit.desktop; 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.widget.RemoteViews; import android.widget.Toast; /** * Description: * <br/>網站: <a href="http://www.crazyit.org">瘋狂Java聯盟</a> * <br/>Copyright (C), 2001-2014, Yeeku.H.Lee * <br/>This program is protected by copyright laws. * <br/>Program Name: * <br/>Date: * @author Yeeku.H.Lee kongyeeku@163.com * @version 1.0 */ public class StackWidgetProvider extends AppWidgetProvider { public static final String TOAST_ACTION = "org.crazyit.desktop.TOAST_ACTION"; public static final String EXTRA_ITEM = "org.crazyit.desktop.EXTRA_ITEM"; @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // 建立RemoteViews對象,加載/res/layout目錄下的widget_layout.xml文件 RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout); Intent intent = new Intent(context, StackWidgetService.class); // 使用intent更新rv中stack_view組件(StackView) rv.setRemoteAdapter(R.id.stack_view, intent); //① // 設置當StackWidgetService提供的列表項爲空時,直接顯示empty_view組件 rv.setEmptyView(R.id.stack_view, R.id.empty_view); // 建立啓動StackWidgetProvider組件(做爲BroadcastReceiver)的Intent Intent toastIntent = new Intent(context, StackWidgetProvider.class); // 爲該Intent設置Action屬性 toastIntent.setAction(StackWidgetProvider.TOAST_ACTION); // 將Intent包裝成PendingIntent PendingIntent toastPendingIntent = PendingIntent .getBroadcast(context, 0, toastIntent, PendingIntent.FLAG_UPDATE_CURRENT); // 將PendingIntent與stack_view進行關聯 rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent); // 使用AppWidgetManager經過RemteViews更新AppWidgetProvider appWidgetManager.updateAppWidget( new ComponentName(context, StackWidgetProvider.class), rv); //② super.onUpdate(context, appWidgetManager, appWidgetIds); } @Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); } @Override public void onDisabled(Context context) { super.onDisabled(context); } @Override public void onEnabled(Context context) { super.onEnabled(context); } // 重寫該方法,將該組件當成BroadcastReceiver使用 @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(TOAST_ACTION)) { // 獲取Intent中的數據 int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0); // 顯示Toast提示 Toast.makeText(context, "點擊第【" + viewIndex + "】個列表項", Toast.LENGTH_SHORT).show(); } super.onReceive(context, intent); } }
widget_layout.xmlthis
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="8dp"> <StackView android:id="@+id/stack_view" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:loopViews="true" /> <TextView android:id="@+id/empty_view" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:background="#ff0f" android:textColor="#ffffff" android:textStyle="bold" android:text="@string/no_item" android:textSize="20sp" /> </FrameLayout>
Manifest.xmlspa
<?xml version="1.0" encoding="utf-8" ?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.crazyit.desktop" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:label="@string/app_name"> <!-- 配置AppWidgetProvider,即配置桌面控件 --> <receiver android:name=".StackWidgetProvider"> <!-- 經過該intent-filter指定該Receiver做爲桌面控件 --> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <!-- 爲桌面控件指定meta-data --> <meta-data android:name="android.appwidget.provider" android:resource="@xml/stackwidgetinfo" /> </receiver> <!-- 配置RemoteViewsService 必須指定權限爲android.permission.BIND_REMOTEVIEWS --> <service android:name=".StackWidgetService" android:permission="android.permission.BIND_REMOTEVIEWS" android:exported="false" /> </application> </manifest>
stackwidgetinfo.xml
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="110dp" android:minHeight="110dp" android:updatePeriodMillis="3600000" android:previewImage="@drawable/ic_launcher" android:initialLayout="@layout/widget_layout" android:resizeMode="horizontal|vertical" android:autoAdvanceViewId="@id/stack_view"> </appwidget-provider>
截圖: