標籤:
widget包是存放自訂群組件
開發自訂群組件;
其實Android API開發指南中的App Widgets章節 已經說得很清楚了,下面只是對自己的理解進行一次梳理。
--
AppWidget 就是HomeScreen上顯示的小組件,提供直觀的互動操作。通過在HomeScreen中長按,在彈出的對話方塊中選擇Widget組件來進行建立,長按組件後並拖動到垃圾箱裡進行刪除。同一個Widget組件可以同時建立多個。
AppWidget的實現主要涉及到以下類:
AppWidgetProvider
RemoteViews
AppWidgetManager
1.
首先需要提供一個定義了Widget介面布局的XML檔案(位於res/layout/..),需要注意的是使用的組件必須是RemoteViews所支援的,目前原生API中支援的組件如下:
FrameLayout
LinearLayout
RelativeLayout
AnalogClock
Button
Chronmeter
ImageButton
ImageView
ProgressBar
TextView
*如果使用了除此之外的組件,則在Widget建立時會導致android.view.InflateExceptionn異常。
PS:這就導致有一些功能或樣式無法實現,如很基本的list或文本編輯框都是無法直接實現的。如果想自訂Widget中的View的話只能通過修改framework來提供相應組件的支援。
2.
然後需要提供一個xml檔案來定義Widget的基本屬性,放置到res/xml/..目錄下。
如果使用的是Eclipse可按如下操作:
1) 在res/目錄下建立xml/目錄
2)建立xml檔案(名字可任意),選擇類型為AppWidgetProvider
3)在彈出的便捷介面進行參數設定
主要設定的參數如下:
minWidth: 定義Wdiget組件的寬度
minHeight: 定義Wdiget組件的高度
updatePeriodMillis: 更新的時間周期
initialLayout: Widget的布局檔案
configure: 如果需要在啟動前先啟動一個Activity進行設定,在這裡給出Activity的完整類名(後面會說到,與一般Activity的實現有些許差別)
*Widget大小的計算儲存格數*74)-2,API上說是為了防止像素計算時的整數舍入導致錯所以-2...不是很明白
一個完整的範例:
Xml代碼 收藏代碼
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="80dp"
android:minHeight="32dp"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/widget_provider"
android:configure="com.demo.widget.MyWidgetConfiguration" >
</appwidget-provider>
3.
xml都定義好後,接下來就是建立一個繼承自AppWidgetProvider的子類,AppWidgetProvider實際上就是一個BroadcastReceiver,裡面提供了以下函數:
onReceive(Context, Intent)
onUpdate(Context , AppWidgetManager, int[] appWidgetIds)
onEnabled(Context)
onDeleted(Context, int[] appWidgetIds)
onDisabled(Context)
可通過重寫以上函數來監聽Widget狀態的變化並進行相應的處理。
以上函數具體調用情況歸納如下:
[啟動 - 無confiure Activity]
onReceive
onEnabled —— 第一個widget被顯示
onReceive
onUpdate —— 重新整理介面
[啟動 - 帶confiuration Activity]
onReceive
onUpdate
[拖動]
<無狀態變化>
[周期更新]
onReceive
onUpdate
[刪除]
onReceive
onDeleted —— widget被刪除
onReceive
onDisabled —— 最後一個widget被移除
[啟動時位置不夠]
onReceive
onEnabled
onReceive
onUpdate
onReceive
onDeleted
onReceive
onDisabled
*每次狀態的變化會觸發onReceive,一般該函數是不需要重寫的。
簡單瞭解AppWidgetProvider之後,我們來看具體實現。
這裡建立一個MyAppWidgetProvider繼承AppWidgetProvider:
Java代碼 收藏代碼
public class MyWidgetProvider extends AppWidgetProvider {
static final String TAG = "widget";
/**
* 更新
*/
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
Log.i(TAG, "onUpdate");
}
/**
* 第一個Widget組件啟動時觸發
*/
public void onEnabled(Context context){
Log.i(TAG, "onEnabled");
}
/**
* 最後一個Widget組件關閉時觸發
*/
public void onDisabled(Context context){
Log.i(TAG, "onDisabled");
}
/**
* 任一Widget組件被刪除時觸發
*/
public void onDeleted(Context context, int[] appWidgetIds){
Log.i(TAG, "onDeleted");
}
/**
* 以上函數觸發前會先觸發該函數,一般不需要重寫
*/
public void onReceive(Context context, Intent intent){
Log.i(TAG, "onReceive");
super.onReceive(context, intent);
}
}
其中onUpdate顧名思義是對Widget進行更新的,前面定義的更新周期就是作用於該函數的。
Widget的更新與Activity不同,必須藉助於RemoteViews和AppWidgetMananger。具體實現如下:
Java代碼 收藏代碼
public void onUpdate(Context context, AppWidgetMananger appWidgetManager, int[] appWidgetIds){
int N = appWidgetIds.length; // 可能啟動了多個Widget,appWidgetIds記錄了這些Widget的ID
for(int i=0; i<N; i++){
RemoteViews views = new RemoteViews(getPackageName(), R.layout.widget_views);
appWidgetManager.updateAppWidget(appWidgetIds[i], views);
}
}
其中需要注意的是,雖然RemoteViews參數都是一樣的,但是對於每個Widget最好都新建立一個再進行傳遞,否則會導致一些錯誤。具體可參考AppWidget RemoteViews 記憶體溢出 。
其他函數的可以根據需要實現。
由於無法擷取到RemoteViews建立的介面中的元素,對於Widget中組件的操作只能通過RemoteViews所提供的有限的函數進行,常用的有:
setOnClickPendingIntent(int viewId, PendingIntent pendingIntent)
setProgressBar(int viewId, int max, int progress, boolean indeterminate)
setTextViewText(int viewId, CharSequence text)
setViewVisibility(int viewId, int visibility)
詳細函數列表可參考API中的RemoteViews類 。
4.
最後,更新AndroidManifest.xml。
AppWidgetProvider對應一個receiver屬性:
Xml代碼 收藏代碼
<receiver android:name="MyWidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"></action>
</intent-filter>
<meta-data android:resource="@xml/widget_property" android:name="android.appwidget.provider"></meta-data>
</receiver>
5.
提供Configuration Activity
Configuration Activity是一個在Widget啟動前先啟動的Activity,方便使用者對Widget的屬性進行設定。
在res/xml/...下對應的"屬性檔案"中添加configure欄位指定啟動的Activity,並在AndroidManifest.xml中該Activity下提供一個action為android.appwidget.action.APPWIDGET_CONFIGURE 的IntenFilter。
需要注意的是,
如果設定了Configure屬性,則必須在指定的Activity中進行如下處理:
1.在onCreate中setContentView()函數前添加setResult(RESULT_CANCLE) ,這樣如果在Activity初始化完成前按下了BACK按鍵,則Widget不會啟動;
2.在setContentView()函數之後(不一定要在onCreate中,在Activity退出前即可),添加如下設定以指定需要啟動的Widget:
Java代碼 收藏代碼
int mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
否則會導致退出Activity後Widget不啟動。
>> Widget建立步驟匯總:
1.定義Widget布局XML -> res/layout/...
2.定義Widget屬性檔案(xml) -> res/xml/...
3. 建立AppWidgetProider子類,實現onUpdate()等函數,在manifest中註冊receiver,添加一個action為 android.appwidget.action.APPWIDGET_UPDATE 的IntentFilter,並添加如下<meta- data>標識:
Xml代碼 收藏代碼
<meta-data android:resource="@xml/<屬性檔案xml>" android:name="android.appwidget.provider"></meta-data>
4. 建立Coniguration Activity(注意處理好setResult),添加到屬性檔案中的Configure屬性,在manifest中註冊activity,添加一個 action為android.appwidget.action.APPWIDGET_CONFIGURE 的IntentFilter
最後附上一個完整的例子,
實現思路如下:
1. 提供一個Configuration Activity,這裡只簡單顯示一行文字;
2.退出後Widget啟動;
3.點擊Widget中的按鈕會啟動一個Activity
(轉自:http://quding0308.iteye.com/blog/1164276)
android widget包說明與應用