LayoutInflater.SetFactory()學(xué)習(xí)(2)

參考1
參考2
完整github代碼

一:LayoutInflaterFactory的用途:

自行創(chuàng)建自定義的View,而不是讓系統(tǒng)去創(chuàng)建,可以避免系統(tǒng)的反射過程,提升性能;
在XML使用自定義View的時候,可以不聲明全限定名稱;
更換系統(tǒng)View為自己定義View,這正是Appcompat庫替換默認的系統(tǒng)View的方式。

二:使用LayoutInflaterFactory的方式

(1)自定義LayoutInflaterFactory

通過繼承Support Library的LayoutInflaterFactory,在Activity里面設(shè)置自定義的LayoutInflaterFactory

@Override public void onCreate(Bundle savedInstanceState) {
    LayoutInflaterCompat.setFactory(getLayoutInflater(), new MyLayoutInflaterFactory(this));
    super.onCreate(savedInstanceState);
    ...
}

注意:super.onCreate(savedInstanceState);之前設(shè)置自定義LayoutInflaterFactory;否則自定義的LayoutInflaterFactory不會生效。
LayoutInflater factories的最大限制是一個factory只能綁定一個LayoutInflater,因為support library已經(jīng)綁定自己的factory;設(shè)置自定義的LayoutInflaterFactory可能會帶來一些問題,比如無法從XML文件中加載Fragment,無法加載v21包里面的屬性;

官方文檔:
如果使用自定義的Factory,可以忽略調(diào)用 installViewFactory 方法,然后直接調(diào)用 createView() 方法 返回兼容的View;

document

也就是說自定義LayoutInflaterFactory負責(zé)調(diào)用

AppCompatDelegate#createView(android.view.View, String, android.content.Context, android.util.AttributeSet

下面這個方法可以克服一個LayoutInflater只能設(shè)置一個LayoutInflaterFactory的缺陷;它會創(chuàng)建一個新的LayoutInflater實例,然后綁定你可以給它綁定自定義的Factory;它是通過合并自定義factory和support library的 factory 來實現(xiàn)的;如果調(diào)用這個方法來創(chuàng)建LayoutInflater實例,需要在Activity中重寫getLayoutInflater()getSystemService(String)來返回自己的LayoutInflater

LayoutInflater#cloneInContext(Context)
(2)使用Activity作為LayoutInflaterFactory

所有的LayoutInflater都設(shè)置了一個默認的LayoutInflaterFactory,Activity默認實現(xiàn)了Factory和Factory2;
這樣在Activity中就允許 override下面的兩個方法來處理自定義view的加載。

View onCreateView(View, String, Context, AttributeSet);
View onCreateView(String, Context, AttributeSet);

三:LayoutInflater Factory創(chuàng)建方法

(1)一個在XML文件中的移除自定義View全限定名稱的 Factory

移除自定義View全限定名稱的好處:(1)如果自定義View被重構(gòu)(refactor)了,不用在XML文件中修改;(2)增強可讀性
一個Factory的例子

public class MyLayoutInflaterFactory implements LayoutInflaterFactory {
    @Override
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
        if (TextUtils.equals(name, "DebugDrawerLayout")) {
            return new DebugDrawerLayout(context, attrs);
        } else if (TextUtils.equals(name, "ScrimInsetsFrameLayout") {
            return new ScrimInsetsFrameLayout(context, attrs);
        }
        // and so on...
    }
}

上面代碼的問題: 如果按照上面的寫法可能要列出所有的自定義View,然后一個個判斷;
改進為使用反射的方式創(chuàng)建;

public class MyLayoutInflaterFactory implements LayoutInflaterFactory {
    private static final String CUSTOM_VIEWS_PACKAGE = "com.example.ui.customviews.";

    private static final Class<?>[] constructorSignature = new Class[] { 
            Context.class, AttributeSet.class };

    @Override
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
        Constructor<? extends View> constructor = null;
         //通過classLoader來加載類(全限定名稱);
        Class<? extends View> clazz = context.getClassLoader()
                .loadClass(CUSTOM_VIEWS_PACKAGE + name).asSubclass(View.class);
          //獲取構(gòu)造函數(shù)
        constructor = clazz.getConstructor(constructorSignature);
        constructor.setAccessible(true);
        return constructor.newInstance(context, attrs);
    }
}

上面代碼的缺陷是沒有反射cache;

四:如何在自定義LayoutInflaterFactory中保留support library的特性;

public class CustomViewsLayoutInflaterFactory implements LayoutInflaterFactory {
    private AppCompatDelegate appCompatDelegate;

    public CustomViewsLayoutInflaterFactory(AppCompatDelegate appCompatDelegate) {
        this.appCompatDelegate = appCompatDelegate;
    }

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

        // todo: your custom inflation code here!

        if (result == null) {
            // Get themed views from AppCompat
            result = appCompatDelegate.createView(parent, name, context, attrs);
        }
        return result;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,917評論 25 709
  • afinalAfinal是一個android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,857評論 2 45
  • DataBinding 庫是 Google 公司 Android Framework UI 工具團隊開發(fā)出來的一款...
    bravian閱讀 5,512評論 2 16
  • 其實,很早就想寫一篇舞蹈的文章了。 當然最近跟我聊舞的人也蠻多的。 因為我知道,很多女孩也都跟我一樣,一直有一個“...
    梓涼閱讀 1,319評論 2 0
  • 之七 汕大圖書館,此行一重點, 外觀并無奇,方形很平淡。 內(nèi)部有洞天,設(shè)計實堪贊: 中庭為天井,回字形擴展, 四條...
    沁園春M閱讀 215評論 2 3

友情鏈接更多精彩內(nèi)容