1. 程式人生 > >android外掛化主題方案 (上--LayoutInflateFactory的使用)

android外掛化主題方案 (上--LayoutInflateFactory的使用)

android外掛化主題方案 (上–LayoutInflateFactory的使用)

標籤(空格分隔): android 主題 面板 外掛化

“做成網易音樂那樣的!”
這次產品經理提出的需求就是像網易音樂那樣可以更換主題面板,當然面板切換很多app都有,產品經理也明確表示需要後臺有面板主題管理能力,所以這次的功能免不了要做成外掛式,不能簡單的在資原始檔編寫多套value的方式實現。
那我們就來一步步的實現吧。

首先,我們先不管外掛化的方式,先來看看如何在不更改已編寫xml的情況下,快速替換view的資源。

setContentView()做了些什麼?
我們知道預設onCreate()

執行時,馬上會呼叫setContentView(int id)方法,將layout資源與activity進行繫結,我們看看setContentView做了些什麼。

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

這是Activity類中的setContentView()的方法,我們繼續往下看。

@Override  
public void setContentView(int layoutResID) {  
   if (mContentParent == null) {  
       installDecor();  
   } else {  
       mContentParent.removeAllViews();  
   }  
   mLayoutInflater.inflate(layoutResID, mContentParent);  
   final Callback cb = getCallback();  
   if (cb != null && !isDestroyed()) {  
       cb.onContentChanged();  
   } 
}  

在這裡我們看到了熟悉的充氣類,我們View的建立離不開Inflate,那麼它在建立View的時候做了什麼呢?

   public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
   ....
       final View temp = createViewFromTag(root, name, inflaterContext, attrs);
       ...
}

我們找到這個建立view的方法

 View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
        boolean ignoreThemeAttr) {
        ...
          View view;
        if (mFactory2 != null) {
            view = mFactory2.onCreateView(parent, name, context, attrs);
        } else if (mFactory != null) {
            view = mFactory.onCreateView(name, context, attrs);
        } else {
            view = null;
        }
        if (view == null && mPrivateFactory != null) {
            view = mPrivateFactory.onCreateView(parent, name, context, attrs);
        }
        ...
        }

最終我們的view是通過factory進行建立的,
而這個factory就是我們這次需要重點介紹的工具。

   /**
 * Used with {@code LayoutInflaterCompat.setFactory()}. Offers the same API as
 * {@code LayoutInflater.Factory2}.
 */
public interface LayoutInflaterFactory {
    /**
     * Hook you can supply that is called when inflating from a LayoutInflater.
     * You can use this to customize the tag names available in your XML
     * layout files.
     *
     * @param parent The parent that the created view will be placed
     * in; <em>note that this may be null</em>.
     * @param name Tag name to be inflated.
     * @param context The context the view is being created in.
     * @param attrs Inflation attributes as specified in XML file.
     *
     * @return View Newly created view. Return null for the default
     *         behavior.
     */
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs);}

LayoutInflateFactory是一個介面,其只有一個方法,我們重點關注註釋,簡單理解為

提供給你一個鉤子(可以理解為監聽),用以在inflate的時候用名字作為比對,生成對應的View物件進行返回。

so,整個inflate的過程大致就是,xmlParser對xml進行解析,然後傳遞至Factory根據名字生產相對應的View類,然後返回上層進行新增,好了,下面,我們就可以通過實現這個介面,在onCreate()中對生成的view設定各種屬性,這樣,我們就能在xml中書寫固定的資源情況下,動態對view的屬性進行更改。

自定義Factory

 @Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {

    boolean isSkinEnable = attrs.getAttributeBooleanValue(SkinConfig.NAMESPACE, SkinConfig.ATTR_SKIN_ENABLE, false);
    AppCompatDelegate delegate = mAppCompatActivity.getDelegate();
    View view = delegate.createView(parent, name, context, attrs);
    if (view instanceof TextView && SkinConfig.isCanChangeFont()) {
        TextViewRepository.add(mAppCompatActivity, (TextView) view);
    }

    if (isSkinEnable || SkinConfig.isGlobalSkinApply()) {
        if (view == null) {
            view = ViewProducer.createViewFromTag(context, name, attrs);
        }
        if (view == null) {
            return null;
        }
        parseSkinAttr(context, attrs, view);
    }
    return view;
}

這裡的isSkinEnable我們用來在xml標記該view需要更換面板(自定義名稱空間),下面判斷TextView的部分用來處理更換字型,暫且不看,其餘的建立View的方法於原始碼相同,建立View之後,我們用parseSkinAttr()方法進行view的處理,當然之前我們需要判斷該view是否需要進行切換。
在這個方法中,我們就可以對這個view進行各種處理,更改背景,更改imageView的src等等。
waring
這個factory只用於在介面初始化(比如開啟一個activity)的時候進行主題的更改,在介面被繪製完畢後,我們需要更改這個介面所有view的屬性的話,得呼叫其他方法,所以為了標記那些view需要更改,我們在這個方法中可以定義一個集合,在初始化的時候進行儲存,以方便後續處理。

  SkinItem skinItem = new SkinItem();
        skinItem.view = view;
        skinItem.attrs = viewAttrs;
        mSkinItemMap.put(skinItem.view, skinItem);

skinItem就是需要更改的view及其屬性的封裝物件。
替換activity的factory為自定義的factory

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

這裡我建議書寫一個baseActivity,在super.onCreate之前將activity與Factory進行繫結。

這樣在每一個activity啟動之後,建立view時,我們都可以控制到該view的屬性,而我們將這些view儲存之後,我們同樣可以在activity已經建立完畢的條件下,準確找到需要更改的view並對其做相應的修改操作。

相關推薦

android外掛主題方案 --LayoutInflateFactory的使用

android外掛化主題方案 (上–LayoutInflateFactory的使用) 標籤(空格分隔): android 主題 面板 外掛化 “做成網易音樂那樣的!” 這次產品經理提出的需求就是像網易音樂那樣可以更換主題面板,當然面板切換很多app

Android外掛的相容性Android O的適配

      首先宣告,《Android外掛化開發指南》這本書所介紹的Android底層是基於Android6.0(API level 23)的,而本書介紹的各種外掛化解決方案,以及配套的70多個例子,在Android7.0(API level 24)手機上測試都是能正常工作的。      如果讀者您的手機是

Android外掛系列第篇---外掛載入機制兩種方案

一、相關概念 1.1、為什麼需要動態載入 這個問題,前面已經介紹過,如下 Android系統使用了ClassLoader機制來進行Activity等元件的載入;apk被安裝之後,APK檔案的程式碼以及資源會被系統存放在固定的目錄(比如/d

Android外掛最佳方案--Phantom 實踐指南

PhantomTest 滿幫集團外掛化框架Phantom使用演示 Phantom外掛化演示(請star支援) 演示demo下載 注意:請將外掛apk拷貝至sdcard下。 Phantom介紹 Phantom 是滿幫集團開源的一套穩定、靈

Android外掛——Replugin入門

一、360Replugin簡介 RePlugin是一套完整的、穩定的、適合全面使用的,佔坑類外掛化方案,由360手機衛士的RePlugin Team研發,也是業內首個提出”全面外掛化“(全面特性、全面相容、全面使用)的方案。 其主要優勢有: 極其靈活:主程式無需升級(無

Android外掛開發教程

1.什麼是外掛化開發首先我們要對外掛化的概念有一個認識:外掛化開發是將整個app拆分成很多模組,這些模組包括一個宿主和多個外掛,每個模組都是一個apk(元件化的每個模組是個lib),最終打包的時候將宿主apk和外掛apk分開或者聯合打包。外掛式開發通俗的講就是把一個很大的app分成n多個

Android外掛的相容性Android P的適配

     Android系統的每次版本升級,都會對原有程式碼進行重構,這就為外掛化帶來了麻煩。      Android P對外掛化的影響,主要體現在兩方面,一是它重構了H類中Activity相關的邏輯,另一個是它重構了Instrumentation。      3.1 H類的變身      3.1

Android 語音播報實現方案無SDK

功能描述 類似支付寶收款時候的語音播報功能:當別人掃描你的收款碼,你收到錢之後,就會聽到“支付寶到賬12.55元”的語音播報。 要解決的問題 1.播放單個語音檔案 2.播放完單個語音檔案之後立即播放下一條,這樣才能連續 3.當多個完整的語音

4.6.29Android外掛框架總結

一、概述 所謂外掛化,就是讓我們的應用不必再像原來一樣把所有的內容都放在一個apk中,可以把一些功能和邏輯單獨抽出來放在外掛apk中,然後主apk做到[按需呼叫],這樣的好處是一來可以減少主apk的體積,讓應用更輕便,二來可以做到熱插拔,更加動態化 採集

Android 外掛分析3- Activity啟動流程

在真正分析外掛化技術前,我們必須瞭解一些必要的關於Android四大元件的相關知識。 以Activity為例,我們需要了解Activity啟動過程,才能有效的進行Hook實現外掛化。 以Android 8.1為例 我們啟動一個Activity通常會使用startActi

【轉載】Android外掛常見衝突解決方案

文章轉自:https://blog.csdn.net/xiangzhihong8/article/details/80278068在Android元件化和外掛化的過程中,經常會遇到狠多的問題,如常見的包依賴衝突,資原始檔依賴衝突等問題,當然,在資原始檔上面,一些元件化框架已為

Android外掛原理和實踐 (六) 之 四大元件解決方案

在前面的幾篇文章中已經介紹完了Android外掛化的第一和第二個根本問題,就是宿主和外掛的程式碼互相呼叫問題和外掛中資源的讀取問題。現剩下的就是Android外掛化裡最麻煩的第三個根本問題,也就是在外掛中使用四大元件的問題。我們知道,目前外掛中的四大元件要想正常使用就必須要在宿主中的Androi

Android外掛探索資源載入

前情提要 PathClassLoader和DexClassLoader的區別 DexClassLoader的原始碼如下: public class DexClassLoader extends BaseDexClassLoader {

Android 淘氣三千傳之 —— 外掛的一點理解()

外掛化 這一篇主要是個人對外掛化涉及到的一些基礎知識的理解,內容都比較簡單: 包括以下內容: 目錄: 1、類載入機制 2、Binder機制 3、APP、四大元件的啟動流程 4、APK安裝過程 5、資源的載入過程 6、Hook

Android 熱修復與外掛 一】帶你入門Android外掛附demo

本文為博主Colin原創文章,歡迎轉載。 https://blog.csdn.net/colinandroid/article/details/79431502   一. 背景 Android外掛化作為每個合格的Android程式設計師都必須會的技術,被各大廠廣泛使用。隨著各大廠對

包建強的培訓課程10Android外掛從入門到精通

Android外掛化和熱修復 一.簡介 本課程結合講師多年來對Android外掛化技術的潛心研究,以及在千萬級使用者的App上長期實踐經驗,整理而成。本課程從四大元件的外掛化技術講起,中途會詳細剖析Android系統中與外掛化技術有關的底層概念,最後詳細介紹業界流行很廣的外

Android外掛學習之路之使用外掛中的R資源

res裡的每一個資源都會在R.java裡生成一個對應的Integer型別的id,APP啟動時會先把R.java註冊到當前的上下文環境,我們在程式碼裡以R檔案的方式使用資源時正是通過使用這些id訪問res資源,然而外掛的R.java並沒有註冊到當前的上下文環境,所

Android外掛原理Activity外掛

相關文章 前言 四大元件的外掛化是外掛化技術的核心知識點,而Activity外掛化更是重中之重,Activity外掛化主要有三種實現方式,分別是反射實現、介面實現和Hook技術實現。反射實現會對效能有所影響,主流的外掛化框架沒有采用此方式,關於介面實

Android外掛學習之路之動態建立Activity

靜態代理Activity模式的限制 我們在代理Activity模式一文裡談到啟動外掛APK裡的Activity的兩個難題嗎,由於外掛裡的Activity沒在主專案的Manifest裡面註冊,所以無法經歷系統Framework層級的一系列初始化過程,最終導致獲得

Android外掛學習之路之動態載入綜述

前段時間,公司專案完成了外掛化的開發,自己也因此學習了很多Android外掛化的知識,於是想把這些內容記錄下來,本次帶來Android外掛化的第一篇:動態載入綜述 背景知識 1.什麼是動態載入? 動態載入技術應由以下幾個部分組成: 1) 應用在執行