- Android 5從入門到精通
- 李波
- 2403字
- 2021-03-19 15:29:00
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();
- Mastering phpMyAdmin 3.4 for Effective MySQL Management
- C語言程序設計
- Mastering Yii
- PostgreSQL Replication(Second Edition)
- 實戰Java高并發程序設計(第3版)
- Python編程:從入門到實踐
- BIM概論及Revit精講
- C# Multithreaded and Parallel Programming
- Learning Splunk Web Framework
- Learning Kotlin by building Android Applications
- 讓Python遇上Office:從編程入門到自動化辦公實踐
- 高質量程序設計指南:C++/C語言
- C語言程序設計
- SOA Patterns with BizTalk Server 2013 and Microsoft Azure(Second Edition)
- C語言程序設計