By 何明桂(http://blog.csdn.net/hmg25) 轉載請註明出處
之前分析了下widget添加到laucher的過程,現在我們來分析下widget被添加到laucher之後發生的故事。
AppWidgetProvider
案頭組件實現的組要類,它的父類是一個廣播接收器,它主要作用就是接收更新案頭組件的廣播訊息,然後更新案頭組件
i. public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds):
該方法對應事件:android.appwidget.action.APPWIDGET_UPDATE,當案頭組件被周期更新的時候它被調用,深入父類的onReceive方法就會瞭解到,當父類的onReceive方法接收到android.appwidget.action.APPWIDGET_UPDATE訊息就會調用該update方法。
ii. public void onReceive(Context context, Intent intent):
AppWidgetProvider本身是一個廣播接收器,父類已經覆蓋了該方法,你重新覆蓋該方法的時候,注意要添加super. onReceive到你的方法中,否則onUpdate將不再會被調用
iii. public void onDeleted(Context context, int[] appWidgetIds):
AppWidgetProvider接收訊息android.appwidget.action.APPWIDGET_DELETED時候調用該方法。
每個案頭組件就是一個AppWidget,當你需要在代碼中實現一個案頭組件,首先你必須得實現AppWidgetProvider類,當你點擊AppWidgetProvider類你會發現其實AppWidgetProvider就是一個BroadcastReceiver子類,也就是說它也是一個廣播接收器。案頭組件內容顯示更新全部是通過RemoteViews對象,剛建立案頭組件的時候系統會綁定AppWidgetProvider到一個AppWidgetId,然後後面通過AppWidgetManager.updateAppWidget方法把RemoteViews對象更新到對應的案頭組件。
回到之前添加widget時的流程,在案頭組件剛被添加的時候,系統通過AppWidgetHost.allocateAppWidgetId函數為案頭組件分配一個新的AppWidgetId。在選擇widget的時候,通過點擊的列表選項可擷取到對應案頭組件對應的ComponentName,一個ComponentName由一個包名和一個AppWidgetProvider類名稱唯一指定,然後通過AppWidgetManager.bindAppWidgetId(int appWidgetId, ComponentName provider)把前面產生的AppWidgetId與一個ComponentName綁定,一個ComponentName可以綁定多個AppWidgetId。所以你可以在案頭上放置幾個一樣的widget。
一個AppWidgetProvider可以由一個ComponentName唯一確定,在一般的widget應用中:
//先擷取一個AppWidgetManager對象<br /> AppWidgetManager appWidgetMgr = AppWidgetManager.getInstance(context);<br />//建立一個ComponentName對象,用來擷取擷取案頭組件widgetIds<br /> ComponentName compName = new ComponentName(context,<br /> ExampleWidgetProvider.class);<br />//返回的是由 ComponentName對應的 int[] widgetIds<br /> int[] widgetIds = appWidgetMgr.getAppWidgetIds(compName);
每一個AppWidgetProvider上可能建立了多個案頭組件,每一個案頭組件對以應一個AppWidgetId,要擷取一個AppWidgetProvider上所有的案頭組件的AppWidgetId資料,可以先建一個ComponentName對象,設定ComponentName中的類名和包名為AppWidgetProvider的類名和包名,然後可通過AppWidgetManager. getAppWidgetIds(ComponentName provider)方法擷取AppWidgetId列表。
通過AppWidgetId我們便可以操作指定的widget。
widget介面的更新是通過RemoteViews日哦,而RemoteViews並不是一個真正的View,它沒有實現View的介面,而只是一個用於描述View的實體。比如:建立View需要的資源ID和各個控制項的事件回應程式法。RemoteViews會通過處理序間通訊機制傳遞給AppWidgetHost。
AppWidgetHost和AppWidgetHostView是在framework中定義的兩個基類。應用程式可以利用這兩個類來實現自己的Host。Launcher是預設的案頭,它是一個Host的實現者。
LauncherAppWidgetHostView擴充了AppWidgetHostView,實現了對長按事件的處理。
LauncherAppWidgetHost擴充了AppWidgetHost,這裡只是重載了onCreateView,建立LauncherAppWidgetHostView的執行個體。
Remoteviews更新案頭組件最終還是要在launcher進程中執行,在launcher中有一個handler: AppWidgetHost.UpdateHandler,該handler就是用來處理Remoteviews更新的,一旦我們調用appWidgetManager.updateAppWidget(appWidgetId, views)這個方法,AppWidgetHost.UpdateHandler. handleMessage事件就會響應,不過要注意是該事件響應是在launcher進程中執行:
switch (msg.what) {<br /> case HANDLE_UPDATE: {<br /> updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);//執行Remoteviews更新<br /> break;<br /> }