官术网_书友最值得收藏!

3.5 App Widgets

App Widgets是指能夠嵌入到其他應用程序中的小組件,并且能夠周期性地進行更新。App Widgets并不是Android應用程序的核心組件,但應用程序開發確實是不可或缺的部分。我們可以通過App Widgets使UI界面更多樣化,也可以通過App Widget provider發布我們自己開發的App Widgets組件。一個能夠用于容納App Widgets組件的應用程序組件被稱為App Widgets Host(App Widgets宿主),例如下圖所示的音樂播放程序。

圖3.3 App Widgets Host

Android5中涉及的部分App Widgets類的使用方法會在第四章進行詳細介紹,本部分主要對如何使用App Widget Provider發布自己的App Widget組件的方法進行簡單介紹。

3.5.1 基礎知識

為了創建一個自己的App Widget,需要完成以下工作:


●AppWidgetProviderInfo元數據


定義在XML文件中的用于描述App Widget的元數據對象,比如App Widget的布局,更新頻率,以及相關的AppWidgetProvider類。


●實現AppWidgetProvider類


在AppWidgetProvider類中定義了一系列方法,這些方法允許開發者以編程的方式和自己的App Widget進行交互,這種交互基于廣播事件。當App Widget的狀態發生改變,例如更新、啟用、禁用和刪除的時候,你都會接收到相應的廣播通知。


●視圖布局


在XML文件中為App Widget定義初始布局。


●實現App Widget配置Activity


這是一個可選的Activity,當用戶添加App Widget時該Activtity會被啟動,并允許用戶在創建App Widget時修改相關設置。

下面進行詳細介紹。

3.5.2 在Manifest文件中聲明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資源路徑。

3.5.3 增加AppWidgetProviderInfo元數據

AppWidgetProviderInfo用于定義App Widget的一系列基本特性,例如最小布局的尺寸,初始的布局資源、刷新頻率以及創建時要加載的配置Activity等。使用<appwidget-provider>元素標簽在XML中定義AppWidgetProviderInfo對象并保存到項目的res/xml/目錄下。例如:

    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
        android:minWidth="294dp" <!-- density-independent pixels -->
        android:minHeight="72dp"
        android:updatePeriodMillis="86400000" <!-- once per day -->
        android:initialLayout="@layout/example_appwidget"
        android:configure="com.example.android.ExampleAppWidgetConfigure" >
    </appwidget-provider>

其中:


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

●updatePerdiodMillis屬性定義了App Widget框架調用onUpdate()方法來從AppWidgetProvider請求一次更新的頻率。實際上更新的時間并不精準。建議更新頻率越低越好,比如一小時更新一次,這樣可以節省電力,或者根據用戶的配置調整更新頻率,比如有個人每15分鐘想查看一下股票的報價,這樣可以將頻率設置為一小時更新四次。

●initialLayout屬性指向App Widget使用的布局的資源

●configure屬性定義了該App Widget被加載時使用的配置Activity。

3.5.4 創建App Widget布局

必須在res/layout目錄下以xml文件方式為App Widget定義一個布局文件。App Widget的布局是基于RemoteViews對象,而RemoteViews對象可以支持以下布局:

    Framelayout
    LinearLayout
    RelativeLayout
    GridLayout

和以下的小組件類:

    AnalogClock
    Button
    Chronometer
    ImageButton
    ImageView
    ProgressBar
    TextView
    ViewFlipper
    ListView
    GridView
    StackView
    AdapterViewFlipper

但是并不支持它們的派生類。

此外,RemoteView還支持ViewStub,該組件不可見,自身無尺寸,可用于對布局資源進行支撐。

3.5.5 為App Widget添加邊界

若沒有為自定義的Widget定義邊界,它就會自動擴展到屏幕大小。因此,我們需要為自定義的App Widget定義邊界。

自Android4.0開始,App Widget會自動在Widget的邊界環繞盒之間添加空隙,以便為Widget和其他小組件以及屏幕上的圖標提供更好的排列組合方式。為實現這一個行為,我們需要將應用程序中的“targetSdkVersion”屬性設置為大于14。

實際上,我們可以自己定義一個帶有自定義邊界的布局,并且使該布局在應用于早期平臺版本時正常顯示邊界,而在Android4.0以后版本的平臺上不顯示額外邊界。定義過程如下:

(1)設置targetSdkVersion為大于14的值

(2)創建一個布局,并為其設置dimension資源,其邊界信息由dimension資源設定。代碼如下:

        <FrameLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:padding="@dimen/widget_margin">



      <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:background="@drawable/my_widget_background">
        …
      </LinearLayout>



    </FrameLayout>

(3)創建兩個dimension資源,一個在res/values/目錄下,用于提供早于Android4.0版本的系統的邊界信息,另外一個在res/values-v14下,用于提供高于Android4.0版本的操作系統的邊界信息。

例如,res/values/dimens.xml定義如下:

    <dimen name="widget_margin">8dp</dimen>

而res/values-v14/dimens.xml定義如下:

    <dimen name="widget_margin">0dp</dimen>

3.5.6 使用AppWidgetProvider類

首先,AppWidgetProvider類是BroadcastReceiver類的子類,可以方便地處理App Widget發出的廣播,因此,其必須被聲明在清單文件中的<receiver>元素中。AppWidgetProvider只接受和相應的App Widget相關的廣播消息,例如這個App Widget被更新、被刪除、被啟用或者被禁用的時候。當這些廣播事件發生的時候,AppWidgetProvider會接收到以下一系列方法的調用請求:


●onUpdate():每間隔一定時間該方法就會被調用用于對App Widget進行更新。間隔時間由AppWidgetProviderInfo 元數據中的updatePeriodMillis 屬性指定。當用戶添加App Widget時該方法也會被調用。因此該方法中應該執行必要的操作,例如為視圖定義事件處理器或者啟動一個臨時的服務等。如果你為App Widget定義了配置Activity,則應該由配置Activity負責進行第一次更新,而onUpdate()方法不會在用戶執行添加操作的時候被調用,而只會在后期的更新時被調用。

●onAppWidgetOptionsChanged():該方法在當Widget被首次放置到應用程序中或者Widget的尺寸被更改時被調用。

●onDeleted(Context, int[]):該方法在App Widget被從App Widget宿主中刪除的時候被調用。

●onEnabled(Context):該方法在App Widget的第一個實例被創建時被調用。如果用戶添加了兩個App Widget的實例,則該方法只會在第一次添加時被調用。如果你需要進行打開數據庫或者進行其他只需要進行一次的設置,那么將代碼放在這個方法中是個不錯的主意。

●onDisabled(Context):該方法在最后一個App Widget實例從App Widget宿主中被刪除的時候調用。在該方法中你應該對在onEnabled()方法中的操作進行善后,例如刪除一個臨時的數據庫。

●onReceive(Context, Intent):每當接收到一個廣播,該方法都會被調用。并且,該方法會在上述各個方法之前被調用。通常我們不需要重寫該方法,因為默認的AppWidgetProvider類已經很好地實現了對所有廣播的過濾和處理方法的調用。


可見onUpdate()方法是最重要的回調方法,如果你創建的App Widget不需要進行創建臨時文件等操作的話,那么你可能只需要定義onUpdate()方法就可以了。例如,當你創建了一個帶有Button的App Widget,當單擊按鍵時會啟動一個Activity,那么你的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);
            }
        }
    }

其中appWidgetIds是一個存放ID的數組,其中的每一個ID值都標識一個AppWidgetProvider創建的App Widget。如果該數組中存放了多個App Widget的ID,那么這些App Widget會被同步更新。

3.5.7 接收App Widget的廣播

如果你想直接用自己的類接收并處理App Widget的廣播,那么你需要實現自己的BroadcastReceiver,重寫onReceiver()方法,并處理以下四個intent:


●ACTION_APPWIDGET_UPDATE

●ACTION_APPWIDGET_DELETED

●ACTION_APPWIDGET_ENABLED

●ACTION_APPWIDGET_DISABLED

3.5.8 創建App Widget的配置Activity

如果想讓用戶在添加新的App Widget的時候對顏色、尺寸、更新周期等屬性進行配置,那么就需要創建一個配置Activity。配置Activity會在App Widget被創建時由其宿主啟動。

該配置Activity需要在Manifest文件中進行聲明,通過ACTION_APPWIDGET_CONFIGURE活動被宿主啟動。代碼如下:

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

此外,該Activity還需要在AppWidgetProviderInfo XML中通過android:configure屬性被聲明。例如:

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

當為App Widget定義了配置Activity后,Widget在被創建時不會再調用onUpdate方法。

3.5.9 使用配置Activity對App Widget進行更新

當Widget使用了配置Activity后,配置Activity會在用戶完成設置后對Widget進行更新。通過配置Activity對Widget進行更新并關閉配置Activity的過程如下:

(1)首先,從啟動Activity的Intent中獲取到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)完成配置后,獲取AppWidgetManager類的實例

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

(4)通過RomoteViews布局對App Widget進行更新

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

(5)最后,創建返回Intent,設置Activity返回值,并關閉Activity。

       Intent resultValue = new Intent();
    resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
    setResult(RESULT_OK, resultValue);
    finish();
主站蜘蛛池模板: 荆州市| 兴宁市| 桂平市| 武功县| 太白县| 正定县| 宣武区| 禄劝| 招远市| 永丰县| 静宁县| 宁都县| 延庆县| 鹰潭市| 湛江市| 通河县| 尤溪县| 昌都县| 阿尔山市| 务川| 颍上县| 克山县| 明水县| 南澳县| 大石桥市| 邵东县| 乌兰浩特市| 扎兰屯市| 临桂县| 昭觉县| 聂拉木县| 土默特左旗| 望城县| 利辛县| 九龙城区| 高陵县| 华蓥市| 合肥市| 牟定县| 杭锦后旗| 雷山县|