最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android用于加載xml的LayoutInflater源碼超詳細(xì)分析

 更新時(shí)間:2022年08月26日 15:27:56   作者:niuyongzhi  
今天不想去聊一些Android的新功能,新特性之類的東西,特別想聊一聊這個(gè)老生常談的話題:LayoutInflater,感興趣的朋友來看看吧

1.在view的加載和繪制流程中:文章鏈接

我們知道,定義在layout.xml布局中的view是通過LayoutInflate加載并解析成Java中對(duì)應(yīng)的View對(duì)象的。那么具體的解析過程是哪樣的。

先看onCreate方法,如果我們的Activity是繼承自AppCompactActivity。android是通過getDelegate返回的對(duì)象setContentView,這個(gè)mDelegate 是AppCompatDelegateImpl的實(shí)例。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 }
 //getDelegate 返回的是AppCompatDelegateImpl的實(shí)例
  public void setContentView(@LayoutRes int layoutResID) {
        this.getDelegate().setContentView(layoutResID);
  }
  public AppCompatDelegate getDelegate() {
        if (mDelegate == null) {
            mDelegate = AppCompatDelegate.create(this, this);
        }
        return mDelegate;
    }
    public static AppCompatDelegate create(@NonNull Activity activity,
            @Nullable AppCompatCallback callback) {
        return new AppCompatDelegateImpl(activity, callback);
    }

在AppDelegateImpl中

  public void setContentView(int resId) {
        this.ensureSubDecor();
        //contentParent 是 系統(tǒng)布局文件 id 為content的view
        ViewGroup contentParent = (ViewGroup)this.mSubDecor.findViewById(android.R.id.content));
        contentParent.removeAllViews();
        LayoutInflater.from(this.mContext).inflate(resId, contentParent);
        this.mOriginalWindowCallback.onContentChanged();
  }

resource 就是傳遞過來的layout資源id,系統(tǒng)通過XmlPullParser來解析xml。Root是上面得到的contentView。

 public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
         final Resources res = getContext().getResources();
         final XmlResourceParser parser = res.getLayout(resource);
         try {
             return inflate(parser, root, attachToRoot);
         } finally {
             parser.close();
         }
  }

name 就是定義在布局文件中的控件名字,LinearLayout,TextView等,包括自定義的控件

attrs定義在控件下所有屬性,包括寬高顏色背景等。

先通過createViewFromTag拿到布局文件中的root view。

再通過rInflateChildren遍歷子View。

最后root.addView(temp, params);將布局文件的root view 添加到contentView中,成為它的一個(gè)子View。

 public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
   final AttributeSet attrs = Xml.asAttributeSet(parser);
     final String name = parser.getName();
   //在layout.xml中找到的root view
    final View temp = createViewFromTag(root, name, inflaterContext, attrs);
   // Create layout params that match root, if supplied
      params = root.generateLayoutParams(attrs);
    // Inflate all children under temp against its context.
    //遍歷布局文件中定義的子view,將定義在xml的view轉(zhuǎn)換成對(duì)應(yīng)的java對(duì)象。
      rInflateChildren(parser, temp, attrs, true);
    if (root != null && attachToRoot) {
        //將layout中定義的root view 加到contentView中
         root.addView(temp, params);
    }
 }

createViewFromTag方法,通過name和attrs創(chuàng)建View對(duì)象。

再調(diào)用rInflateChildren 加載子View,通過循環(huán)遍歷,把整個(gè)layout樹轉(zhuǎn)換成Java的View對(duì)象。

  final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
            boolean finishInflate) throws XmlPullParserException, IOException {
        rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
    }
//開始遍歷子view
    void rInflate(XmlPullParser parser, View parent, Context context,
               AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
        while (((type = parser.next()) != XmlPullParser.END_TAG ||
                parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
            .......
            final View view = createViewFromTag(parent, name, context, attrs);
            final ViewGroup viewGroup = (ViewGroup) parent;
            final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
            rInflateChildren(parser, view, attrs, true);
            viewGroup.addView(view, params);
         }
    }

createViewFromTag是創(chuàng)建View對(duì)象的關(guān)鍵方法。

有兩種方式,一種是繼承自AppCompactActivity,會(huì)通過factory的onCreateView創(chuàng)建view。

另外一種是繼承自Activity,沒有設(shè)置factory,或者通過factory創(chuàng)建view失敗,則調(diào)用onCreateView方法進(jìn)行創(chuàng)建。

 //將定義在xml的標(biāo)簽通過反射成對(duì)應(yīng)的java對(duì)象。
     View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
                boolean ignoreThemeAttr) {
            // 當(dāng)Activity繼承自AppCompactActivity時(shí),會(huì)在AppCompactActivity,onCreate時(shí)調(diào)用
            // delegate.installViewFactory()設(shè)置factory,然后調(diào)用factory的方法創(chuàng)建view
           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);
            }
            //當(dāng)Activity繼承自Activity時(shí),沒有設(shè)置factory時(shí),執(zhí)行下面的創(chuàng)建過程
			//或者通過上面的方式?jīng)]有加載到View,也會(huì)調(diào)用下面的方法創(chuàng)建view對(duì)象。
            if (view == null) {
                final Object lastContext = mConstructorArgs[0];
                mConstructorArgs[0] = context;
                try {
                    if (-1 == name.indexOf('.')) {
                        view = onCreateView(parent, name, attrs);
                    } else {
                        view = createView(name, null, attrs);
                    }
                } finally {
                    mConstructorArgs[0] = lastContext;
                }
            }
            return view;
      }

先看第一種方法:調(diào)用factory的onCreateView方法,是通過調(diào)用mAppCompatViewInflater.createView創(chuàng)建的,根據(jù)name和attrs,直接調(diào)用View的構(gòu)造函數(shù)創(chuàng)建的對(duì)象。創(chuàng)建的都是一些系統(tǒng)內(nèi)置的view對(duì)象。

final View createView(View parent, final String name, @NonNull Context context,
            @NonNull AttributeSet attrs, boolean inheritContext.....){
  View view = null;
        // We need to 'inject' our tint aware Views in place of the standard versions
        switch (name) {
            case "TextView":
                view = createTextView(context, attrs);
                verifyNotNull(view, name);
                break;
            case "ImageView":
                view = createImageView(context, attrs);
                verifyNotNull(view, name);
                break;
            case "Button":
                view = createButton(context, attrs);
                verifyNotNull(view, name);
                break;
            case "EditText":
                view = createEditText(context, attrs);
                verifyNotNull(view, name);
                break;
            .............
         return view;
}

再看第二種方式:通過反射進(jìn)行創(chuàng)建。通過反射的方式,可以創(chuàng)建自定義的view對(duì)象。

public final View createView(@NonNull Context viewContext, @NonNull String name,
            @Nullable String prefix, @Nullable AttributeSet attrs){
       Class<? extends View> clazz = null;
          clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
                        mContext.getClassLoader()).asSubclass(View.class);
          constructor = clazz.getConstructor(mConstructorSignature);
           constructor.setAccessible(true);
           //將得到的構(gòu)造函數(shù)保存的map中
           sConstructorMap.put(name, constructor);
     final View view = constructor.newInstance(args);
     return view;
}

通過以上兩種方式,就可以完成整個(gè)layout 的Java 對(duì)象轉(zhuǎn)換。

然后就可以調(diào)用view的繪制的方法,執(zhí)行view繪制流程。onlayout,onMeasure,ondraw。

app換膚的的框架可以通過設(shè)置自定義的Factory來實(shí)現(xiàn)。這塊有機(jī)會(huì)再寫文章探討。

到此這篇關(guān)于Android用于加載xml的LayoutInflater源碼超詳細(xì)分析的文章就介紹到這了,更多相關(guān)Android LayoutInflater 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android后臺(tái)模擬點(diǎn)擊探索(附源碼)

    Android后臺(tái)模擬點(diǎn)擊探索(附源碼)

    這篇文章主要介紹了Android后臺(tái)模擬點(diǎn)擊探索(附源碼),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • Android性能測試關(guān)注的指標(biāo)整理

    Android性能測試關(guān)注的指標(biāo)整理

    在本篇文章里小編給各位整理的是關(guān)于Android性能測試關(guān)注的指標(biāo)整理內(nèi)容,有興趣的朋友們學(xué)習(xí)下。
    2019-10-10
  • flutter直接上傳文件到阿里云oss

    flutter直接上傳文件到阿里云oss

    上傳視頻到oss,之前是走后端上傳到oss,會(huì)有一個(gè)問題就是我要先上傳給后端,后端再上傳給oss就會(huì)導(dǎo)致上傳多次,消耗時(shí)間過長影響用戶體驗(yàn),所以我參考文檔寫了直接上傳到阿里云oss獲取到文件訪問路徑。
    2021-05-05
  • Android 應(yīng)用的全屏和非全屏實(shí)現(xiàn)代碼

    Android 應(yīng)用的全屏和非全屏實(shí)現(xiàn)代碼

    這篇文章主要介紹了Android 應(yīng)用的全屏和非全屏實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 安卓自定義流程進(jìn)度圖控件實(shí)例代碼

    安卓自定義流程進(jìn)度圖控件實(shí)例代碼

    本篇文章主要介紹了安卓自定義流程進(jìn)度圖控件實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • 阿里路由框架ARouter 源碼解析之Compiler

    阿里路由框架ARouter 源碼解析之Compiler

    這篇文章主要介紹了阿里路由框架ARouter 源碼解析之Compiler,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-07-07
  • Android  回調(diào)詳解及簡單實(shí)例

    Android 回調(diào)詳解及簡單實(shí)例

    這篇文章主要介紹了Android 回調(diào)詳解及簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • Android仿QQ空間主頁面的實(shí)現(xiàn)

    Android仿QQ空間主頁面的實(shí)現(xiàn)

    今天模仿安卓QQ空間,打開程序的啟動(dòng)畫面和導(dǎo)航頁面我就不做了,大家可以模仿微信的那個(gè)做一下,很簡單。這次主要做一下主頁面的實(shí)現(xiàn),感興趣的朋友可以參考下
    2013-01-01
  • Android 自定義View步驟

    Android 自定義View步驟

    這篇文章主要介紹了Android 自定義View步驟 的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-06-06
  • 基于SQLite的Android登錄APP

    基于SQLite的Android登錄APP

    這篇文章主要為大家詳細(xì)介紹了基于SQLite的Android登錄APP,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-01-01

最新評(píng)論

乌恰县| 漳浦县| 浦北县| 洱源县| 咸丰县| 鹤峰县| 永嘉县| 宁明县| 屯留县| 松桃| 喜德县| 英超| 内黄县| 洛隆县| 都昌县| 库尔勒市| 垣曲县| 洪雅县| 苗栗县| 定州市| 宁都县| 隆德县| 五原县| 肥乡县| 台安县| 曲松县| 烟台市| 丹凤县| 肥城市| 禹州市| 章丘市| 巢湖市| 贡嘎县| 余姚市| 佛山市| 天峻县| 永丰县| 宁陕县| 柳林县| 勐海县| 新巴尔虎左旗|