Android中RemoteViews的實現

來源:互聯網
上載者:User

田海立@CSDN

2012-8-22

 

本文結合AppWidget的應用情境,分析Android中RemoteViews的內部具體實現。

從前文《Android中AppWidget的分析與應用:AppWidgetProvider》和《Android中Launcher對於AppWidget的處理的分析:AppWidgetHost角色》中得知,Android中AppWidget的圖形資源是由AppWidgetProvider通過RemoteViews提供的;而顯示是由AppWidgetHost通過AppWidgetHostView把RemoteView提供的內容顯示在本地View上的。AppWidgetProvider和AppWidgetHostView運行在不同的程式中,而它們溝通的圖形元素和點擊回饋的橋樑就是RemoteViews。

 

下面為了行文方便和一致,把RemoteViews的內容提供方AppWidgetProvoder稱作Remote端;而顯示RemoteViews內容的一方AppWidgetHost稱作Local端。

 

一、給RemoteViews提供內容——SettingsAppWidgetProvider

 

是SettingsAppWidgetProvider(位於Settings中的com.android.settings.widget包中)作為AppWidgetProvider得到update通知之後,建立RemoteViews,並把Remote端的響應Intent以及圖形元素放進RemoteViews中的順序圖。


圖一、為RemoteViews提供內容和偵聽

 

圖中,

1.        Settings建立RemoteViews時,把packageName和layoutId傳進去並儲存起來。packageName相當重要,因為這裡的layoutId和各種其他資源都是相對這個程式來說的,只有通過packageName獲得相應的Context,才能進而獲得資源,否則其他程式是無法獲得這些資源的[Seq#1]。

2.        Settings把layoutId中的viewId指示的View被點擊之後獲得響應的PendingIntent設定到RemoteViews中[Seq#2~ #5]。

  •  RemoteViews建立SetOnClickPendingIntent並把id和intent傳入,SetOnClickPendingIntent儲存這些值;
  •  SetOnClickPendingIntent是RemoteViews.Action的子類,通過addAction()把SetOnClickPendingIntent加入到mActions:ArrayList<RemoteViews.Action>儲存下來。

3.        Settings把layoutId中的viewId指示的View的ImageSourceID設定到RemoteViews中[Seq#6~ #10]。

  •  RemoteViews中有很多setXYZ()的方法,用來根據不同的要設定值的類型來設定;
  •  setXYZ()建立ReflectionAction並把viewId和value,以及“setImageResource”作為methodName傳入,ReflectionAction儲存這些值;
  •  ReflectionAction是RemoteViews.Action的子類,通過addAction()把ReflectionAction加入到mActions:ArrayList<RemoteViews.Action>儲存下來。

這裡描述的是一個子過程,後續會通過AppWidgetManager把這個建立好的RemoteViews放進AppWidget系統中,從而使得AppWidget的AppWidgetHost端更新顯示RemoteViews裡承載的內容。

 

Remote端設定內容的過程,只是設定這些參數,而RemoteViews也只是用不同的RemoteViews.Action儲存了這些參數。下文描述內部結構。

注意:這裡的參數都是在Remote端的,在RemoteContext有效。

 

二、RemoteViews的內部結構

 

是RemoteViews相關的類圖。


圖二、RemoteViews類圖

 

RemoteViews中儲存Remote端的mPackage和mLayoutId;並用mActions:ArrayList<RemoteViews.Action>儲存各種Action。

mPackagemLayoutId是在構造RemoteViews時傳進去的[上文圖中的seq#1];

mActions是設定各種Remote端的響應Intent以及圖形元素的時候,儲存到相應的Action中,然後把Action加入到這裡儲存的;

mLayoutId裡的各種控制項通過setTextViewText()/ setImageViewResource() / setProgressBar(),等函數在remote端設定的。這些方法再調用setType() [Type可為Boolean / Byte / Short / Int/ Long / Char / String / Uri / Bitmap/ Bundle, etc]儲存到ReflectionAction中。

SetOnClickPendingIntent是用來在local端使用者點擊viewId時,發出pendingIntent通知的。在SetOnClickPendingIntent的構造方法中儲存viewId和pendingIntent。

ReflectionAction用來在local端顯示時,通過Reflect機制執行獲得Remote端資源的。在ReflectionAction的構造方法中儲存viewId,methodName,type以及value。

ViewGroupActionSetDrawableParameters也是RemoteViews.Action的子類,在這個情境中並未用到,基本原理相似,讀者可自行分析。

 

三、顯示RemoteViews內容——AppWidgetHostView

 

圖一中為RemoteViews提供了內容之後,AppWidgetHost會通過IAppWidgetHost.updateAppWidget()被通知到Remote端有更新,本地端把RemoteViews提供的內容顯示在AppWidgetHostView上。下面的順序圖描述這一過程。


圖三、本地顯示RemoteViews裡的內容

 

圖中:

1.      擷取RemoteViews裡Remote端(AppWidgetProvider)的packageName和layoutId,通過packageName建立遠端的context——remoteContext。[Seq#1~ 6]

2.      通過RemoteViews的apply()方法,真正開始執行偵聽Click操作的動作;通過遠端Layout獲得本地使用的View。[Seq#7~ 20]

2.1.  複製一個本地的LayoutInflater;[Seq#8]

2.2.  用複製出的LayoutInflater對remote端的layoutId執行Inflate,獲得Layout所描述的View的Hierarchy,亦即後面用到的rootView;[Seq#9~ 10]

2.3.  對2.2中獲得的view執行performApply。[Seq#11~ 19]

performApply()對所有mActions中的Action都執行apply()操作。這樣,

2.3.1 對於setOnClickPendingIntent來說,[Seq#12~ 15]

  •  通過rootView(2.2獲得的Remote端的Layout的總的View)的findViewById(viewId),找到要偵聽的View;[Seq#13]
  •  對找到的要偵聽的View設定Click的Listener。[Seq#14]

2.3.2對於ReflectionAction來說,[Seq#16~ 19]

  •  通過rootView(2.2獲得的Remote端的Layout的總的View)的findViewById(viewId),找到要設定內容的對象View;[Seq#17]
  •  然後通過Reflect機制,執行View實作類別裡的方法(比如這裡是setImageResource()),把相應的資源的Id設定給它. [Seq#18]

3.      把獲得的View加入到本地的View系統中。[Seq#21]

 

下面是ReflectionAction.apply()通過Reflect機制設定內容的程式碼片段(忽略了出錯處理和非關鍵區段):

       @Override       public void apply(View root) {           final View view = root.findViewById(viewId);           Class param = getParameterType();  // 通過this.type得到class:int.class           Class klass = view.getClass();     // 這個類在Remote的Layout中定義,這裡為ImageView           Method method = klass.getMethod(this.methodName, param); // methodName是實現View類裡的方法名:setImageResource(int)            try {               // 執行ImageView.setImageResource(value),value為resId                method.invoke(view, this.value);           } catch (Exception ex) {               throw new ActionException(ex);           }        }

 

四、總結

RemoteViews的內容提供方,提供顯示的資源和偵聽點擊事件的Intent;

RemoteViews的本地顯示方,通過RemoteViews獲得View中的顯示資源,並加入到本地的圖形系統中,完成Remote資源的本地顯示。

 

可進一步參考的文章

通過這一系列的其他文章,可獲得與本文關聯的資訊:

Android AppWidget架構

    AppWidget系統架構。

Android中選取並綁定AppWidget

    Launcher發起選取過程,此文中描述選取並綁定的過程,可結合本文看完整的選取/綁定/加入顯示系統的完整過程。

Android中AppWidget的分析與應用:AppWidgetProvider

    是此文所描述的AppWidgetProvider建立RemoteViews,並設定了ImageViewResource和OnClickPendingIntent。

Android中Launcher對於AppWidget處理的分析:AppWidgetHost角色

    此文描述的AppWidgetProvider提供的RemoteViews,在Launcher中開始真正應用RemoteViews的時機。

Android中RemoteViews的實現

    本文。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.