Android 視窗小組件 App Widgets

來源:互聯網
上載者:User

應用程式視窗小組件App Widgets

應用程式視窗小組件(Widget)是微小的應用程式視圖,可以被嵌入到其它應用程式中(比如案頭)並接收周期性的更新。你可以通過一個App Widget provider來發布一個Widget。可以容納其它App Widget的應用程式組件被稱為App Widget宿主。下面的截屏顯示了一個音樂App Widget。

這篇文章描述了如何使用App Widget Provider發布一個App Widget。

 

基礎知識The Basics

為了建立一個App Widget,你需要下面這些:

AppWidgetProviderInfo 對象

描述一個App Widget中繼資料,比如App Widget的布局,更新頻率,以及AppWidgetProvider 類。這應該在XML裡定義。

AppWidgetProvider 類的實現

定義基本方法以允許你編程來和App Widget串連,這基於廣播事件。通過它,當這個App Widget被更新,啟用,禁用和刪除的時候,你都將接收到廣播通知。

視圖布局

為這個App Widget定義初始布局,在XML中。

另外,你可以實現一個App Widget配置活動。這是一個可選的活動Activity,當使用者添加App Widget時載入並允許他在建立時來修改App Widget的設定。

 

下面的章節描述了如何建立這些組件:

在清單中聲明一個應用小組件

首先,在應用程式AndroidManifest.xml檔案中聲明AppWidgetProvider 類,比如:

<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>

<receiver>元素需要android:name屬性,它指定了App Widget使用的AppWidgetProvider 。

<intent-filter> 元素必須包括一個含有android:name屬性的<action>元素。該元素指定AppWidgetProvider接受ACTION_APPWIDGET_UPDATE 廣播。這是唯一你必須顯式聲明的廣播。當需要的時候,AppWidgetManager 會自動發送所有其他App
Widget廣播給AppWidgetProvider。

<meta-data> 元素指定了AppWidgetProviderInfo 資源並需要以下屬性:

·         android:name – 指定中繼資料名稱。

·         android:resource – 指定AppWidgetProviderInfo 資源路徑。

 

增加AppWidgetProviderInfo中繼資料

AppWidgetProviderInfo定義一個App Widget的基本特性,比如最小布局尺寸,初始布局資源,重新整理頻率,以及(可選的)建立時載入的一個配置活動。使用單獨的一個<appwidget-provider>元素在XML資源裡定義AppWidgetProviderInfo對象並儲存到項目的res/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>

下面是<appwidget-provider>屬性的總結:

·         minWidth 和minHeight 屬性的值指定了這個App Widget布局需要的最小地區。

預設的App Widgets所在視窗的案頭位置基於有確切高度和寬度的單元網格。如果App Widget的最小長寬和這些網格單元的尺寸不匹配,那麼這個App Widget將收縮到最接近的單元尺寸。(參見App Widget Design Guidelines 以擷取更多關於案頭單元尺寸的資訊)

因為案頭布局方向(由此,單元的尺寸)可以變化,按照拇指規則,你應該假設最壞情況單元尺寸是74像素高和寬。不過,你必須從最後的尺寸中減去2以把像素計算過程中產生的任何的整數舍入誤差考慮在內。要找到像素密度無關的最小寬度和高度,使用這個公式:
(number of cells * 74) - 2
遵循這個公式,你應該使用72dp為每一個單元高度,294dp為四個單元寬度。

·         updatePerdiodMillis 屬性定義了App Widget架構調用onUpdate()方法來從AppWidgetProvider請求一次更新的頻度。實際更新時間並不那麼精確,而且我們建議更新頻率越低越好-也許每小時不超過一次以節省電源。你也許還會允許使用者在配置中調整這個頻率-一些人可能想每15分鐘一次股票報價,或者一天只要四次。

·         initialLayout屬性指向定義App Widget布局的資源。

·         configure屬性定義了Activity ,當使用者添加App Widget時啟動,以為他或她配置App Widget特性。這是可選的(閱讀下面的Creating
an App Widget Configuration Activity)。

參見AppWidgetProviderInfo 類以擷取更多可以被<appwidget-provider>元素接受的屬性資訊。

建立App Widget布局

你必須在XML中為你的App Widget定義一個初始布局並儲存到項目的res/layout/ 目錄下。你可以使用如下所列的視圖對象來設計你的App Widget,但是在此之前,請先閱讀並理解App Widget Design Guidelines.

如果你熟悉在XML中聲明布局,那麼建立這個App Widget布局是很簡單的。但是,你必須意識到那個App Widget布局是基於RemoteViews, 這並不支援所有類型的布局或視圖小組件。

一個RemoteViews對象(以及,相應的,一個App Widget)可以支援下面這個布局類:

·         FrameLayout

·         LinearLayout

·         RelativeLayout

以及下面的小組件類:

·         AnalogClock

·         Button

·         Chronometer

·         ImageButton

·         ImageView

·         ProgressBar

·         TextView

不支援這些類的派生。

使用AppWidgetProvider類

你必須通過在資訊清單檔中使用<receiver>元素來聲明你的AppWidgetProvider 類實現為一個廣播接收器(參見上面的Declaring an App Widget in the Manifest)。

AppWidgetProvider 類擴充BroadcastReceiver 為一個簡便類來處理App Widget廣播。AppWidgetProvider只接收和這個App Widget相關的事件廣播,比如這個App Widget被更新,刪除,啟用,以及禁用。當這些廣播事件發生時,AppWidgetProvider 將接收到下面的方法調用:

onUpdate(Context, AppWidgetManager, int[])

這個方法調用來間隔性的更新App Widget,間隔時間用AppWidgetProviderInfo 裡的updatePeriodMillis屬性定義(參見添加AppWidgetProviderInfo中繼資料)。這個方法也會在使用者添加App Widget時被調用,因此它應該執行基礎的設定,比如為視圖定義事件處理器並啟動一個臨時的服務Service,如果需要的話。但是,如果你已經聲明了一個配置活動,這個方法在使用者添加App
Widget時將不會被調用,而只在後續更新時被調用。配置活動應該在配置完成時負責執行第一次更新。(參見下面的建立一個App Widget配置活動Creating an App Widget Configuration Activity。)

onDeleted(Context, int[])

當App Widget從宿主中刪除時被調用。

onEnabled(Context)

當一個App Widget執行個體第一次建立時被調用。比如,如果使用者添加兩個你的App Widget執行個體,只在第一次被調用。如果你需要開啟一個新的資料庫或者執行其他對於所有的App Widget執行個體只需要發生一次的設定,那麼這裡是完成這個工作的好地方。

onDisabled(Context)

當你的App Widget的最後一個執行個體被從宿主中刪除時被調用。你應該在onEnabled(Context)中做一些清理工作,比如刪除一個臨時的資料庫。

onReceive(Context, Intent)

這個接收到每個廣播時都會被調用,而且在上面的回呼函數之前。你通常不需要實現這個方法,因為預設的AppWidgetProvider實現過濾所有App Widget 廣播並恰當的調用上述方法。

注意: 在Android 1.5中, 有一個已知問題,onDeleted()方法在該調用時不被調用。為了規避這個問題,你可以像Group post中描述的那樣實現onReceive() 來接收這個onDeleted()回調。

 

最重要的AppWidgetProvider 回呼函數是onUpdated(), 因為它是在每個App Widget添加進宿主時被調用的(除非你使用一個配置活動)。如果你的App
Widget 要接受任何使用者互動事件,那麼你需要在這個回呼函數中註冊事件處理器。如果你的App Widget不建立臨時檔案或資料庫,或者執行其它需要清理的工作,那麼onUpdated() 可能是你需要定義的唯一的回呼函數。比如,如果你想要一個帶一個按鈕的App
Widget,當點擊時啟動一個活動,你可以使用下面的AppWidgetProvider實現:

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);        }    }}

這個AppWidgetProvider 僅定義了onUpdated() 方法,為了定義一個PendingIntent,來啟動一個活動並使用setOnClickPendingIntent(int,
PendingIntent)方法把它附著到這個App Widget的按鈕上。注意它包含了一個遍曆appWidgetIds中所有項的迴圈,這是一個IDs數組,每個ID用來標識由這個Provider建立的一個App Widget。這樣,如果使用者建立多於一個這個App Widget的執行個體,那麼它們將被同步更新。不過,對於所有的App Widget執行個體,只有一個updatePeriodMillis 時間表被管理。比如,如果這個更新時間表被定義為每隔兩個小時,而且App Widget的第二個執行個體是在第一個後面一小時添加的,那麼它們將按照第一個所定義的周期來更新而第二個被忽略(它們將都是每2個小時進行更新,而不是每小時)。

注意: 因為這個AppWidgetProvider 是一個廣播接收器BroadcastReceiver,不能保證你的進程在回呼函數返回後仍然繼續運行(參見應用程式基底礎>廣播接收器的生命週期Application Fundamentals > Broadcast
Receiver Lifecycle以擷取更多資訊)。如果你的App Widget設定過程能持續幾秒鐘(也許當執行網頁請求時)而且你要求你的進程繼續,考慮在onUpdated()方法裡啟動一個服務Service 。從這個服務裡,你可以執行自己的App
Widget更新,而不必擔心AppWidgetProvider 由於一個應用程式無響應錯誤Application Not Responding (ANR)而關閉。參見Wiktionary
sample's AppWidgetProvider,這是個App Widget運行一個Service的例子。

同樣參見ExampleAppWidgetProvider.java 例子類。

接收App Widget廣播意圖

 

AppWidgetProvider 只是一個簡便類。如果你想直接接收App Widget 廣播,你可以實現自己的BroadcastReceiver 或者重寫 onReceive(Context,
Intent) 回呼函數。你需要注意的4個意圖如下:

·         ACTION_APPWIDGET_UPDATE

·         ACTION_APPWIDGET_DELETED

·         ACTION_APPWIDGET_ENABLED

·         ACTION_APPWIDGET_DISABLED

 

建立一個App Widget 配置活動

如果你想讓使用者在添加一個新的App Widget時調整設定,你可以建立一個App Widget配置活動。這個活動將被App Widget宿主自動啟動並允許使用者在建立時配置可用的設定,比如App Widget顏色,尺寸,更新周期或者其它功能設定。

這個配置活動應該在Android資訊清單檔中聲明為一個通用活動。不過,它將被通過ACTION_APPWIDGET_CONFIGURE活動而被App Widget宿主啟動,因此這個活動需要接受這個意圖。比如:

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

同樣的,活動必須在AppWidgetProviderInfo XML 檔案中聲明,通過android:configure屬性(參見上面的添加AppWidgetProviderInfo中繼資料Adding the AppWidgetProviderInfo Metadata)。比如,配置活動可以聲明如下:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"    ...    android:configure="com.example.android.ExampleAppWidgetConfigure"    ... ></appwidget-provider>

注意這個活動是用全名聲明的,因為它將從你的程式包外被引用。

這就是所有關於配置活動你一開始需要瞭解的。現在你需要一個真實的活動。這兒就有,不過,當你實現這個活動時記住兩件重要的事情:

•  App Widget 宿主調用配置活動而且配置活動應該總是返回一個結果.這個結果應該包含這個通過啟動該活動的意圖傳遞的App Widget ID(以EXTRA_APPWIDGET_ID儲存在意圖的附加段Intent
extras中)

•  當這個 App Widget 被建立時將不會調用onUpdate() 方法(當一個配置活動啟動時,系統將不會發送ACTION_APPWIDGET_UPDATE廣播).配置活動應該在 App
Widget 第一次被建立時負責從AppWidgetManager請求一個更新.不過, onUpdate() 將在後續更新中被調用-只忽略第一次.

參見下面章節的代碼片斷,該樣本說明了如何從配置中返回一個結果並更新這個App Widget.

 

從配置活動中更新一個App Widget

 

當一個App Widget使用一個配置活動,那麼當配置結束時,就應該由這個活動來更新這個App Widget.你可以直接AppWidgetManager裡請求一個更新來這麼做.

下面是恰當的更新App Widget 以及關閉配置活動這個過程的一個概要描述:

  1. 首先,從啟動這個活動的意圖中擷取App Widget ID:
Intent intent = getIntent(); Bundle extras = intent.getExtras(); if (extras != null) { mAppWidgetId = extras.getInt( AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);

2.  實施你的App Widget 配置。

3.  當配置完成後,通過調用getInstance(Context)擷取一個AppWidgetManager執行個體:

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

      4.  以一個RemoteViews布局調用updateAppWidget(int,
RemoteViews)更新App Widget:

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

     5.  最後,建立返回意圖,設定活動結果,並結束這個活動:

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

提示: 當你的配置活動第一次開啟時,設定活動結果為RESULT_CANCELED。這樣,如果使用者在結束之前從活動外返回,這個App Widget 宿主會接收到配置取消通知而不會添加這個App Widget。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.