標籤:
什麼是Home Screen Widgets
Home screen Widget即稱為小工具或者中文小工具,是顯示在首頁上的views,通過後台進程更新view的資料。
Android由AppWidgetManager來管理系統的widgets。安裝apk後。會依據widget定義在widget列表中顯示該Widget的名稱、表徵圖以及所佔空間,在Android4.0中。以網格方式來顯示,有些OEM廠商會對UI進行又設計一次,widget列表的展現形式會有所不同。
我們長按widget列表中的某個widget。將其拖拽到首頁上。實際上是AppWidgetManager在首頁上建立該widget的一個執行個體(instance)。
能夠有多個執行個體,不同執行個體用widgetID來區分它們。
widget定義兩個重要的java 類,一個是widget configurator activity。在widget執行個體產生時,被AppWidgetManager通過intent喚起進行初始化配置,當中action名為android.appwidget.action.APPWIDGET_CONFIGURE,這個java類是可選的,通常在此進行配置資料的輸入和儲存。因為資料量少。能夠非常方便地儲存在shared preference中。
假設我們建立了兩個widget執行個體,這個配置activity會被調用兩次。
一個Java類。負責管理widget的生命週期,包含當拖拽到首頁時,須要更新時,以及拖入到垃圾桶時的處理。它是AppWidgetProvider的繼承,本質是一個廣播接收器,依據AppWidgetManager發出的廣播資訊。觸發不同的回呼函數,比如widget資料更新時間間隔(在widget定義中給出),widget執行個體的產生和刪除。第一個widget執行個體的產生。最後一個widget執行個體的刪除。
widget在頁面上的產生是由AppWidgetManager依據我們在widget定義中給出的layout檔案產生有關的UI。不是由我們的代碼直接產生,因此我們也無法向在activity中那也直接對widget中的view進行操作,須要通過RemoteViews。提交給AppWidgetManager對某個執行個體進行處理。
小範例
我們將通過小範例。具體解讀怎樣建立一個widget。小範例是一個生日提醒通知器。
在產生widget執行個體時,彈出配置activity,在activity中輸入名字和出生日期。按“設定”button將資料儲存在preference中,並關閉activity。
widget最上的view顯示widget_id:名字,中間左邊顯示距下一次生日的天數。點擊右邊的view可開啟某個網頁,以下顯示出生日期。
定義廣播接收器
前面提到Widget有兩個重要的java類,一個是可選的用於配置的activity,一個用於管理wdiget生命週期的廣播接收器,接收器接收AppWidgetManager的廣播訊息。來觸發各類回呼函數。
我們需在AndroidManifest.xml中定義這兩個java類,以下給出廣播接收器的類定義。
<manifest …… >
<application …… android:label="TestWidget" ……> <!-- android:label就是widget列表中的widget名稱 -->
… …
<receiver android:name=".BirthDayWidgetProvider">
<meta-data android:name="android.appwidget.provider" android:resource="@xml/birthday_widget_provider"/>
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
</receiver>
</application>
</manifest>
這個類是繼承android.appwidget.AppWidgetProvider,通過meta-data設定有關的參數。
這裡補充一下meta-data的知識。最為常見的是採用鍵值對的方式,即<meta-data android:name="xxx" android:value="yyy" />,在組件中能夠獲得該數值,比如在activity中:
ActivityInfo actInfo = mContext.getPackageManager().getActivityInfo( getComponentName(), PackageManager.GET_META_DATA);
String msg = actInfo.metaData.getString("activity_name");
而在service,則為ServiceInfo,在application中為ApplicationInfo。在receiver中為ActivityInfo,但用getReceiverInfo, 假設須要ComponentName參數,能夠用 new ComponentName(context, MyComponent.class)來擷取。
我們看看android.appwidget.AppWidgetManager.java的有關代碼:
/**
* Sent when it is time to update your AppWidget.
*
* This may be sent in response to a new instance for this AppWidget provider having
* been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval} having lapsed, or the system booting.
* ……
*
* @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
*/
public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
/**
* Field for the manifest meta-data tag.
*
* @see AppWidgetProviderInfo
*/
public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
在meta-data中,android.appwidget.provider為Android指定的keyword。用於在相應的resource中定義App Widget Provider資訊的檔案。該檔案位於xml/下。本範例為res/xml/birthday_widget_provider.xml,定義widget的參數。
android.appwdiget.action.APPWIDGET_UPDATE是接收器監聽AppWidgetManger的廣播訊息之中的一個。其它還監聽ACTION_APPWIDGET_ENABLED等等訊息。但在receiver中必須指明是ACTION_APPWIDGET_UPDATE,系統才可識別出接收器實際是widget,才幹在widget列表中加入該widget。其它須要監聽的訊息無需在此列出。
App widget provider的定義
在manifest.xml中。通過meta-data給出appwidget provider定義所在檔案為xml/birthday_width_provider.xml,內容例如以下。
<?
xml version="1.0" encoding="utf-8"?
>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="150dp"
android:minHeight="120dp"
android:updatePeriodMillis="43200000"
android:initialLayout="@layout/birday_widget"
android:configure="cn.wei.flowingflying.testwidget.ConfigBirthDayWidgetActivity"
android:previewImage="@drawable/gift"
android:resizeMode="horizontal|vertical">
</appwidget-provider>
在widget列表中顯示widget的大小為3×2。
在xml中。我們定義長150dp,寬120dp,實際上widget在Home Screen佔領的空間是按網格計算的。每一個網格為74dp×74dp,系統會分配所需容納的網格。一般手機網格為4×4,平板為8×7。
在《Pro Android》一書中給出建議為74的N倍減去2dp(適配邊框),而在Android開發人員網站推薦定義的min長寬為70*N-30。以下是給出的一個範例:
本例間隔時間為12小時(43200000ms)。
Android強烈建議1天最多僅僅有幾次,不要太多。
從Android2.0開始,最小值為30分鐘。
假設我們設定為0。表示不會自己主動update,我們能夠通過AlarmManager類來自行控制何時update。
作為實驗小範例。能夠改為1小時,但不能設定太短,比如1分鐘,在模擬器的實驗中,假設時間間隔太短是不會進行觸發的。
從SDK3.1開始。使用者長按widget,可以resize widget。包含horizontal,vertical和none。要可以resize,要求layout參數可伸縮,注意。假設size改變是沒有callback提醒的。
詳細怎樣resize不太明白。
previewImage是在widget list的表徵圖,假設沒有這項,有用manifest檔案裡定義的main icon。widget列表中的顯示也稱為preview。
配置Activity的定義
在appwidget-provider中通過android:configure定義配置的java類ConfigBirthDayWidgetActivity,這是個普通的activity,須要在AndroidManifest.xml中進行說明,並支援響應APPWIDGET_CONFIGURE action。AndroidManifest.xml的程式碼片段例如以下:
<activity android:name=".ConfigBirthDayWidgetActivity" android:label="配置生日小工具">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
至此。我們完畢了widget的定義。即使我們沒有詳細編寫不論什麼的java類代碼,我們仍能夠將其打包,並在裝置上安裝。安裝後在widget列表中看到我們的小範例TestWidget。
Widget的外觀定義
在appwidget-provider中通過android:initialLayout定義widget的外觀。對應的layout/birday_widget.xml例如以下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="150dp"
android:layout_height="120dp"
android:orientation="vertical"
android:background="@drawable/box1">
<TextView android:id="@+id/bd_name"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="Anonymous"
android:background="@drawable/box1"
android:gravity="center"/>
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView android:id="@+id/bd_days"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="0"
android:gravity="center"
android:textSize="30sp"
android:layout_weight="50"/>
<TextView android:id="@+id/bd_buy"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="20sp"
android:text="Buy"
android:layout_weight="50"
android:background="#FF6633"
android:gravity="center"/>
</LinearLayout>
<TextView android:id="@+id/bd_date"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="2000/1/1"
android:background="@drawable/box1"
android:gravity="center"/>"
</LinearLayout>
和activity不同。不能直接在代碼中擷取view的對象並進行控制。須要通過AppWidgetManager用RemoteViews來進行間接控制。
因此在widget外觀定義中,view須要能支援remote view,包含FrameLayout、LinearLayout、RelativeLayout、AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper。
Android給出widget外觀設計的guideline,見http://developer.android.com/guide/practices/ui_guidelines/widget_design.html。
通過android:background="@drawable/box1",能夠定義外圍輪廓。
res/drawable/box1.xml的內容例如以下:
<?xml version="1.0" encoding="utf-8"?
>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke android:width="4dp" android:color="#888888"/> <!--定義邊框 -->
<padding android:left="2dp" android:top="2dp" android:right="2dp" android:bottom="2dp"/>
<corners android:radius="4dp" />
</shape>
著作權聲明:本文部落格原創文章,部落格,未經同意,不得轉載。
Android學習筆記:Home Screen Widgets(1):大約Widget