<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
1.在view的載入和繪製流程中:文章連結
我們知道,定義在layout.xml佈局中的view是通過LayoutInflate載入並解析成Java中對應的View物件的。那麼具體的解析過程是哪樣的。
先看onCreate方法,如果我們的Activity是繼承自AppCompactActivity。android是通過getDelegate返回的物件setContentView,這個mDelegate 是AppCompatDelegateImpl的範例。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //getDelegate 返回的是AppCompatDelegateImpl的範例 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 是 系統佈局檔案 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,系統通過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中,成為它的一個子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轉換成對應的java物件。 rInflateChildren(parser, temp, attrs, true); if (root != null && attachToRoot) { //將layout中定義的root view 加到contentView中 root.addView(temp, params); } }
createViewFromTag方法,通過name和attrs建立View物件。
再呼叫rInflateChildren 載入子View,通過迴圈遍歷,把整個layout樹轉換成Java的View物件。
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是建立View物件的關鍵方法。
有兩種方式,一種是繼承自AppCompactActivity,會通過factory的onCreateView建立view。
另外一種是繼承自Activity,沒有設定factory,或者通過factory建立view失敗,則呼叫onCreateView方法進行建立。
//將定義在xml的標籤通過反射成對應的java物件。 View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr) { // 當Activity繼承自AppCompactActivity時,會在AppCompactActivity,onCreate時呼叫 // delegate.installViewFactory()設定factory,然後呼叫factory的方法建立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); } //當Activity繼承自Activity時,沒有設定factory時,執行下面的建立過程 //或者通過上面的方式沒有載入到View,也會呼叫下面的方法建立view物件。 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; }
先看第一種方法:呼叫factory的onCreateView方法,是通過呼叫mAppCompatViewInflater.createView建立的,根據name和attrs,直接呼叫View的建構函式建立的物件。建立的都是一些系統內建的view物件。
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; }
再看第二種方式:通過反射進行建立。通過反射的方式,可以建立自定義的view物件。
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); //將得到的建構函式儲存的map中 sConstructorMap.put(name, constructor); final View view = constructor.newInstance(args); return view; }
通過以上兩種方式,就可以完成整個layout 的Java 物件轉換。
然後就可以呼叫view的繪製的方法,執行view繪製流程。onlayout,onMeasure,ondraw。
app換膚的的框架可以通過設定自定義的Factory來實現。這塊有機會再寫文章探討。
到此這篇關於Android用於載入xml的LayoutInflater原始碼超詳細分析的文章就介紹到這了,更多相關Android LayoutInflater 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45