1. 程式人生 > >Android widget桌面小部件與RemoteViewsService

Android widget桌面小部件與RemoteViewsService

概述

android 中桌面外掛主要依賴於AppWidget框架。涉及類:

  • AppWidgetProvider :BroadcastRecevier子類,用於接收更新,刪除通知
  • AppWidgetProvderInfo:AppWidget相關資訊(大小,更新頻率等),xml形式
  • AppWidgetManger:AppWidget管理類,用於向provider傳送訊息
  • RemoteViews:可以在其他程序中執行的類,用於向provider傳送通知。
  • RemoteViewsService : 是一個遠端的服務介面卡 可以請求RemoteViews,管理RemoteViews的服務.
  • RemoteViewsFactory
    : 提供了RemoteViewsFactory用於填充遠端集合檢視。

實現步驟

  1. 宣告AndroidManifest
  2. 定義初始化 xml檔案
  3. 定義 widget佈局Layout xml檔案
  4. 繼承AppWidgetProvider,實現相關邏輯

AndroidManifest.xml:

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

AppWidgetProvider其本質是一個BroadcastReceiver,其中,APPWIDGET_UPDATE是必須的,用於接收broadcast
meta-data聲明瞭AppWidgetProviderInfo對應的資源xml的位置,其中包括Widget

xml佈局檔案、重新整理頻率、最小寬高

res/xml/example_appwidget_info

<appwidget-provider      xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:updatePeriodMillis="86400000"
    android:previewImage="@drawable/preview"
    android:initialLayout="@layout/example_appwidget"
    android:configure="com.example.android.ExampleAppWidgetConfigure" 
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen">
</appwidget-provider>
  • minWidth & minHeight:定義了 Widget 的最小寬高
  • updatePeriodMillis:定義了 Widget 的重新整理頻率
  • initialLayout:Widget 的佈局 Layout 檔案
  • previewImage:當用戶選擇新增 Widget 時的預覽圖片
  • configure:新增Widget時彈出的Widget配置activity,沒有則不設定
  • resizeMode:水平和垂直方向是否可以調整大小,horizontal,vertical,none,horizontal|vertical
  • widgetCategory: Widget 可以顯示的位置, home_screen(桌面),keyguard(鎖屏,5.0以上)
    更多詳細屬性可以參考 AppWidgetProviderInfo

ExampleAppWidgetProvider:

public class ExampleAppWidgetProvider extends AppWidgetProvider {

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        final int N = appWidgetIds.length;

        // Perform this loop procedure for each App Widget that belongs to this provider
        for (int i=0; i<N; i++) {
            int appWidgetId = appWidgetIds[i];

            // Create an Intent to launch ExampleActivity
            Intent intent = new Intent(context, ExampleActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

            // Get the layout for the App Widget and attach an on-click listener
            // to the button
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
            views.setOnClickPendingIntent(R.id.button, pendingIntent);

            // Tell the AppWidgetManager to perform an update on the current app widget
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }
}

Configuration Activity

<activity android:name=".ExampleAppWidgetConfigure">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
    </intent-filter>
</activity>

新增widget時彈出的activity,需要新增android.appwidget.action.APPWIDGET_CONFIGURE過濾器。

注意事項:

  1. Activity 必須返回帶 EXTRA_APPWIDGET_ID 的 result。
  2. 宣告Configuration Activity 後 onUpdate() 在 Widget 新增時不會被呼叫,Activity 需要呼叫 AppWidgetManager.updateAppWidget()完成 Widget 更新。
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
    mAppWidgetId = extras.getInt(
        AppWidgetManager.EXTRA_APPWIDGET_ID,
        AppWidgetManager.INVALID_APPWIDGET_ID);
}

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.example_appwidget);
appWidgetManager.updateAppWidget(mAppWidgetId, views);

Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();

集合檢視RemoteViewsService

上面的方式提供的方式是針對單個widget,如果我們的widget中包含ListView,Gridview等集合檢視的時候.我們就需要藉助一個類RemoteViewsService,繼承RemoteViewsService並複寫onGetViewFactory 返回RemoteViewsFactory

public class StackWidgetRemoteViewsService extends RemoteViewsService {
    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {}
}