多套主題怎麼靈動換膚?APP換膚方案詳細解析!

yilian發表於2020-02-18

背景需求

目前 Android APP換膚大體可分為兩大類:

  • 兩套主題的切換(比如白天/黑夜),使用一個開關按鈕進行切換。
  • 多套主題線上下載並更新。

第一種的實現基本上使用設定本地 Theme來操作,即將所有的資源打包到 APP中,並且根據主題進行切換。 第二種不可能使用第一種的實現方式,因為將所有資源都打包到 APP中缺乏靈活性,不利於活動的更新,並且也會使得 apk包的體積變大。所有第二種的實現必須是支援線上下載的。

方案選擇

配合產品的需求並且能實現換膚的靈動性,我們選擇上述的第二種方案。經過之前的 AndroidIOS成員小組討論,統一覺得可以採用下載壓縮包,並透過解析壓縮包讀取資源進行替換。

壓縮包下載下來後怎麼讀取資源?這裡有兩種方式:

  • 將下載的皮膚包進行解壓縮並且透過檔案流的方式讀取裡面的圖片資源、檔案資源。
  • 將下載的皮膚包載入到 assetManager管理器中,並透過該管理器新建一個 Resource物件,需要換膚的控制元件透過 Resource物件進行讀取資源。

第一種方式需要手動開啟檔案流,並且不同的檔案流有不同的檔案流方式,比如圖片、文字檔案等,還有不同裝置由於解析度載入的資源是不同的,如何合理地去選擇合適的資源去載入也是一個需要解決的問題。

第二種方式需要將皮膚包載入到 assetManager管理器, assetManager管理器新生成的 Resource物件和我們主工程的 Resource物件是相同類的不同物件,可以使用我們熟悉的方式去載入資源(如 resource.getColorresource.getDrawable等)。

基於上述兩種載入資源的方式,這裡選擇第二種方式進行資源的載入與讀取。

具體實施

1、將所需的皮膚包透過網路下載到本地,這裡的皮膚包是一個 apk檔案,為了讓 apk包足夠小,裡面只包含資原始檔。可能有多個皮膚包,比如 theme1.skintheme2.skin......

2、透過後臺獲取需要載入的皮膚包的名字,如theme1.skin,透過呼叫AssetManager物件的addAssetPath方法並生成一個新的Resource物件,如下程式碼:

  AssetManager assetManager = AssetManager.class.newInstance();  //由於addAssetPath()這個方法被隱藏掉了,所以不能直接使用物件直接訪問,
  //這裡使用了反射的方式,作用是將該皮膚包加入到asset管理器中
  Method addAssetPath = assetManager.getClass().getMethod("addAssetPath"
  , String.class);
  addAssetPath.invoke(assetManager, skinPath);
  Resources skinResource = new Resources(
    assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());

3、自定義一個 InflaterFactory的子類, SkinInflaterFactory,重寫 onCreateView(View, String, Context, AttributeSet)方法,對於需要換膚的控制元件進行屬性的解析與儲存,然後對這些換膚的控制元件去第二步的 Resource物件中載入資源並設定到這些控制元件中。

4、在 BaseActivityonCreate方法新建 SkinInflaterFactory物件,並將該 SkinInflateFactory物件設定給 ActivityLayoutInflater物件,如下程式碼:

  protected void onCreate(@Nullable Bundle savedInstanceState) {
      mSkinInflaterFactory = new SkinInflaterFactory();
      LayoutInflaterCompat.setFactory(
        getLayoutInflater(), mSkinInflaterFactory);      super.onCreate(savedInstanceState);
  }

流程圖

多套主題怎麼靈動換膚?APP換膚方案詳細解析!

其他問題

1、如何支援控制元件點選後觸發不同的業務流程?
可以透過自定義一個屬性,如 skin:click="@string/clickAction",主工程的 clickAction="muapp://app/testDefault",皮膚包裡的 clickAction="muapp://app/testClick",透過目前專案中的路由機制觸發不同的跳轉動作。比如說上述預設的跳轉是跳轉到主工程( appmodule名)的 TestDefaultAction(註解 actionName="testDefault")類的 invoke方法中,而更改後會跳轉到主工程( appmodule名)的 TestClickAction(註解 actionName="testClick")類的 invoke方法中。
2、如何支援控制元件的不同行為方式?例如不同的動畫效果等
這個問題和第一個問題的處理方式的類似的,同樣可以透過主工程和皮膚包不同的 tagString文案)處理不同的行為方式。
3、如何處理自定義 View的換膚需求?
可以新增一個方法,將自定義View需要換膚的屬性名(如 background),屬性值(如 background對應的圖片的資源 ID)傳遞到方法中,然後去皮膚包的 Resource物件中尋找是否有相應的可替換的皮膚或者可替換的行為。

總結

看完之後有沒有掌握呢?作為一個程式設計師,要學的東西有很多,而學到的知識點,都是錢(因為技術人員大部分情況是根據你的能力來定級、來發薪水的),技多不壓身。

為了很好的生活,我們要多多學習,增加我們手裡的金錢。尤其經歷了這一疫情,我深深的感受到金錢的重要,所以,我們一定不能停下學習的腳步!

附上我的Android核心技術學習大綱,獲取相關內容來GitHub:
vx:xx13414521

多套主題怎麼靈動換膚?APP換膚方案詳細解析!


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69952849/viewspace-2676125/,如需轉載,請註明出處,否則將追究法律責任。

相關文章