日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

LayoutInflater的工作原理,從解析XML布局文件到創(chuàng)建Java對(duì)象,再到構(gòu)建View樹(shù)

來(lái)源: 責(zé)編: 時(shí)間:2024-05-07 09:07:11 224觀看
導(dǎo)讀LayoutInflater在Android中是一個(gè)非常重要的組件,主要負(fù)責(zé)將XML布局文件實(shí)例化為對(duì)應(yīng)的View對(duì)象。LayoutInflater是一個(gè)抽象類(lèi),不能直接通過(guò)new的方式獲取其實(shí)例,需要通過(guò)Activity.getLayoutInflater()或Context.getSyst

LayoutInflater在Android中是一個(gè)非常重要的組件,主要負(fù)責(zé)將XML布局文件實(shí)例化為對(duì)應(yīng)的View對(duì)象。LayoutInflater是一個(gè)抽象類(lèi),不能直接通過(guò)new的方式獲取其實(shí)例,需要通過(guò)Activity.getLayoutInflater()或Context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)來(lái)獲取與當(dāng)前Context已經(jīng)關(guān)聯(lián)且正確配置的標(biāo)準(zhǔn)LayoutInflater。biX28資訊網(wǎng)——每日最新資訊28at.com

在實(shí)際工作中,有時(shí)會(huì)根據(jù)情況在代碼中自定義控件或者加載布局文件,這就需要用到LayoutInflater。它的作用是用來(lái)獲得布局文件View對(duì)象的。例如,在BaseAdapter的getView方法中,LayoutInflater經(jīng)常被用來(lái)獲取整個(gè)View并返回。biX28資訊網(wǎng)——每日最新資訊28at.com

View itemView= LayoutInflater.from(context).inflate(R.layout.layout_list_item,container,false);

通過(guò)LayoutInflater.from靜態(tài)函數(shù)獲得一個(gè)LayoutInflater實(shí)例,其實(shí)是個(gè)PhoneLayoutInflater對(duì)象:biX28資訊網(wǎng)——每日最新資訊28at.com

public static LayoutInflater from(Context context) {    LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);    if (LayoutInflater == null) {        throw new AssertionError("LayoutInflater not found.");    }    return LayoutInflater;}

LayoutInflater服務(wù)

LAYOUT_INFLATER_SERVICE服務(wù)跟AMS、WMS等服務(wù)不同,完全是APP虛擬的一個(gè)服務(wù),主要作用是:在本地為調(diào)用者創(chuàng)建PhoneLayoutInflater對(duì)象,ContextImpl在注冊(cè)這個(gè)“服務(wù)”的時(shí)候,將工作委托給PolicyManager,利用makeNewLayoutInflater構(gòu)建LayoutInflater。biX28資訊網(wǎng)——每日最新資訊28at.com

registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {    public Object createService(ContextImpl ctx) {        return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());    }});    public static LayoutInflater makeNewLayoutInflater(Context context) {    return sPolicy.makeNewLayoutInflater(context);}

PolicyManager進(jìn)一步調(diào)用com.android.internal.policy.impl.Policy對(duì)象的makeNewLayoutInflater構(gòu)建PhoneLayoutInflater。biX28資訊網(wǎng)——每日最新資訊28at.com

private static final String POLICY_IMPL_CLASS_NAME ="com.android.internal.policy.impl.Policy";public LayoutInflater makeNewLayoutInflater(Context context) {    return new PhoneLayoutInflater(context);}

圖片圖片biX28資訊網(wǎng)——每日最新資訊28at.com

構(gòu)建View樹(shù)

  1. 「讀取 XML 布局文件」:LayoutInflater 讀取 XML 布局文件。XML 文件描述了 UI 的層次結(jié)構(gòu)和視圖組件的屬性。
  2. 「解析 XML」:LayoutInflater 使用 XML 解析器(如 XmlPullParser)來(lái)解析 XML 文件。遍歷 XML 文件中的每一個(gè)元素(通常是一個(gè)視圖組件,如 TextView、Button 等)和屬性。
  3. 「創(chuàng)建 Java 對(duì)象」:LayoutInflater 使用反射來(lái)創(chuàng)建對(duì)應(yīng)的 Java 對(duì)象。例如,如果 XML 中有一個(gè) TextView 元素,LayoutInflater 就會(huì)創(chuàng)建一個(gè) TextView 的實(shí)例。并根據(jù) XML 中的屬性來(lái)設(shè)置實(shí)例的初始狀態(tài)。
  4. 「構(gòu)建 View 樹(shù)」: 隨著 XML 的解析和 Java 對(duì)象的創(chuàng)建,LayoutInflater 會(huì)將這些對(duì)象組織成一個(gè)樹(shù)形結(jié)構(gòu),即 View 樹(shù)。樹(shù)形結(jié)構(gòu)反映了 XML 布局文件中定義的 UI 層次結(jié)構(gòu)。
  5. 「處理布局參數(shù)」: 如果 inflate 方法被調(diào)用時(shí)傳入了父 ViewGroup,并且第三個(gè)參數(shù)為 true,LayoutInflater 會(huì)自動(dòng)為新創(chuàng)建的視圖設(shè)置布局參數(shù)(LayoutParams)。參數(shù)通常與父 ViewGroup 的類(lèi)型相關(guān),以確保視圖能夠正確地在其父容器中布局。
  6. 「返回根視圖」:LayoutInflater 返回構(gòu)建好的 View 樹(shù)的根視圖。根視圖可以被添加到任何 ViewGroup 中,以顯示在 UI 上。

LayoutInflater源碼中按照上面的流程來(lái)構(gòu)建View,同時(shí)添加了些特殊標(biāo)簽的處理邏輯,比如merge、include、stubview等。biX28資訊網(wǎng)——每日最新資訊28at.com

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

XmlResourceParser是包含了XML文件信息的一個(gè)對(duì)象,通過(guò)XmlResourceParser將TAG信息取出,遞歸創(chuàng)建View。biX28資訊網(wǎng)——每日最新資訊28at.com

public XmlResourceParser getLayout(int id) throws NotFoundException {    return loadXmlResourceParser(id, "layout");}
XmlResourceParser loadXmlResourceParser(int id, String type)        throws NotFoundException {    synchronized (mAccessLock) {        TypedValue value = mTmpValue;        <!--獲取一個(gè)TypedValue-->        if (value == null) {            mTmpValue = value = new TypedValue();        }        <!--利用id 查詢layout,并填充TypedValue-->        getValue(id, value, true);        <!--根據(jù)布局文件的路徑,返回解析xml文件-->        if (value.type == TypedValue.TYPE_STRING) {            return loadXmlResourceParser(value.string.toString(), id,                    value.assetCookie, type);        }    }}

TypedValue是與xml定義的資源對(duì)應(yīng)的值,getValue獲取對(duì)應(yīng)xml資源:biX28資訊網(wǎng)——每日最新資訊28at.com

public void getValue(int id, TypedValue outValue, boolean resolveRefs)        throws NotFoundException {    boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);}

mAssets是一個(gè)AssetManager對(duì)象:biX28資訊網(wǎng)——每日最新資訊28at.com

final boolean getResourceValue(int ident,int density, TypedValue outValue, boolean resolveRefs) {   <!--加載資源-->    int block = loadResourceValue(ident, (short) density, outValue, resolveRefs);    if (block >= 0) {        if (outValue.type != TypedValue.TYPE_STRING) {            return true;        }        outValue.string = mStringBlocks[block].get(outValue.data);        return true;     }      return false;  }

AssetManager通過(guò)native函數(shù)加載xml文件信息:biX28資訊網(wǎng)——每日最新資訊28at.com

static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz, jint ident,jshort density,jobject outValue,jboolean resolve){    ...<!--獲取native AssetManager對(duì)象-->    AssetManager* am = assetManagerForJavaObject(env, clazz);    <!--獲取ResTable資源表,這里應(yīng)該有緩存 不能每次都弄一次吧? 所有資源的唯一表嗎?-->    const ResTable& res(am->getResources());    Res_value value;    ResTable_config config;    uint32_t typeSpecFlags;    <!--通過(guò)ResTable獲取資源-->    ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);   ...    uint32_t ref = ident;    if (resolve) {    <!--是否需要二次解析資源-->        block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);    ...    }    return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;}

res.getResource并不是是每次都加載一遍,第一次加載后就能獲得單例ResTable,后面用的都是這個(gè)緩存,只不過(guò)ResTable不會(huì)緩存全部資源,對(duì)于布局、圖像資源等,緩存的都是引用,如果是真實(shí)資源的引用話,還需要通過(guò)res.resolveReference來(lái)解析真正的資源。biX28資訊網(wǎng)——每日最新資訊28at.com

const ResTable* AssetManager::getResTable(bool required) const{    <!--緩存 ResTable,如果非空直接返回-->    ResTable* rt = mResources;    if (rt) {  return rt;   }   ...<!--多個(gè)apk的話,會(huì)有多個(gè)-->    const size_t N = mAssetPaths.size();    for (size_t i=0; i<N; i++) {        Asset* ass = NULL;        ResTable* sharedRes = NULL;        bool shared = true;        <!--找到Asset的路徑-->        const asset_path& ap = mAssetPaths.itemAt(i);        Asset* idmap = openIdmapLocked(ap);        <!--這里的路徑一般都不是目錄-->        if (ap.type != kFileTypeDirectory) {                   if (i == 0) {                  <!--第一個(gè)一般是框架層的系統(tǒng)資源,用的較多,不想每次都解析,需要緩存-->                sharedRes = const_cast<AssetManager*>(this)->mZipSet.getZipResourceTable(ap.path);            }            if (sharedRes == NULL) {                ass = const_cast<AssetManager*>(this)->mZipSet.getZipResourceTableAsset(ap.path);                if (ass == NULL) {                <!--打開(kāi)resources.arsc文件-->                    ass = const_cast<AssetManager*>(this)->openNonAssetInPathLocked("resources.arsc",  Asset::ACCESS_BUFFER,  ap);                    if (ass != NULL && ass != kExcludedAsset) {                        ass = const_cast<AssetManager*>(this)->mZipSet.setZipResourceTableAsset(ap.path, ass);                    }}                if (i == 0 && ass != NULL) {                    <!--緩存第一個(gè)asset-->                    sharedRes = new ResTable();                    sharedRes->add(ass, (void*)(i+1), false, idmap);                    sharedRes = const_cast<AssetManager*>(this)->mZipSet.setZipResourceTable(ap.path, sharedRes);                } } }         ...                 if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {            if (rt == NULL) {                mResources = rt = new ResTable();                updateResourceParamsLocked();            }            if (sharedRes != NULL) {                rt->add(sharedRes);            } else {                rt->add(ass, (void*)(i+1), !shared, idmap);            }  }  .. }    return rt;}

通過(guò)上面的操作,完成了resources.arsc文件的解析,獲得了一個(gè)ResTable對(duì)象,該對(duì)象包含了應(yīng)用程序的全部資源信息(動(dòng)態(tài)加載的先不考慮),之后就可以通過(guò)ResTable的getResource來(lái)獲得指定資源,而對(duì)于xml布局文件,這里獲得的就是一個(gè)引用,需要res.resolveReference二次解析,之后就得到了id對(duì)應(yīng)的資源項(xiàng)。xml布局文件對(duì)應(yīng)的資源項(xiàng)的值是一個(gè)字符串,其實(shí)是一個(gè)布局文件路徑,指向一個(gè)經(jīng)過(guò)編譯的二進(jìn)制格式保存的xml資源文件。有了這個(gè)Xml資源文件的路徑之后,會(huì)再次通過(guò)loadXmlResourceParser來(lái)對(duì)該Xml資源文件進(jìn)行解析,從而得到布局文件解析對(duì)象XmlResourceParser。biX28資訊網(wǎng)——每日最新資訊28at.com

XmlResourceParser loadXmlResourceParser(String file, int id,    int assetCookie, String type) throws NotFoundException {    if (id != 0) {        try {...                  <!--解析xml文件-->            XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);            if (block != null) {                int pos = mLastCachedXmlBlockIndex+1;                if (pos >= num) pos = 0;                mLastCachedXmlBlockIndex = pos;                XmlBlock oldBlock = mCachedXmlBlocks[pos];                if (oldBlock != null) {                    oldBlock.close();                }                <!--緩存-->                mCachedXmlBlockIds[pos] = id;                mCachedXmlBlocks[pos] = block;                <!--返回-->                return block.newParser();         ...

返回XmlResourceParser對(duì)象,進(jìn)而來(lái)實(shí)例化各種View:biX28資訊網(wǎng)——每日最新資訊28at.com

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {    synchronized (mConstructorArgs) {        final AttributeSet attrs = Xml.asAttributeSet(parser);        Context lastContext = (Context)mConstructorArgs[0];        mConstructorArgs[0] = mContext;        View result = root;        try {            int type;            final String name = parser.getName();            <!--Merge標(biāo)簽的根布局不能直接用LayoutInflater進(jìn)行inflate-->            if (TAG_MERGE.equals(name)) {                if (root == null || !attachToRoot) {                    throw new InflateException("<merge /> can be used only with a valid "                            + "ViewGroup root and attachToRoot=true");                }               rInflate(parser, root, attrs, false);            } else {                View temp;                if (TAG_1995.equals(name)) {                    temp = new BlinkLayout(mContext, attrs);                } else {                <!--利用tag創(chuàng)建View-->                    temp = createViewFromTag(root, name, attrs);                }                ViewGroup.LayoutParams params = null;                if (root != null) {                    <!--是否有container來(lái)輔助,或者添加到container中,或者輔助生成布局參數(shù)-->                    params = root.generateLayoutParams(attrs);                    if (!attachToRoot) {                        temp.setLayoutParams(params);                    }                }                <!--如果有必要,遞歸生成子View,并添加到temp容器中-->                rInflate(parser, temp, attrs, true);                    <!--是否需要添加到root的container容器總-->                if (root != null && attachToRoot) {                    root.addView(temp, params);                }                <!--如果不添加root中,返回結(jié)果就是infate出的根布局View,否則就是root根布局-->                if (root == null || !attachToRoot) {                    result = temp;                }            }        }         return result;     }}

inflate的主要作用是生成layout的根布局文件,并且根據(jù)參數(shù)看看是否需要添加container容器中,之后根據(jù)需要調(diào)用rInflate遞歸生成子View。biX28資訊網(wǎng)——每日最新資訊28at.com

void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {    final int depth = parser.getDepth();    int type;    <!--遞歸解析-->    while (((type = parser.next()) != XmlPullParser.END_TAG ||            parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {        if (type != XmlPullParser.START_TAG) {            continue;        }        final String name = parser.getName();        if (TAG_REQUEST_FOCUS.equals(name)) {            parseRequestFocus(parser, parent);        } else if (TAG_INCLUDE.equals(name)) {            // inclue標(biāo)簽,不能用在getDepth() == 0            if (parser.getDepth() == 0) {                throw new InflateException("<include /> cannot be the root element");            }            parseInclude(parser, parent, attrs);        } else if (TAG_MERGE.equals(name)) {            <!--merge標(biāo)簽必須是布局的根元素,因此merge使用方式一定是被inclue-->            throw new InflateException("<merge /> must be the root element");        } else if (TAG_1995.equals(name)) {            final View view = new BlinkLayout(mContext, attrs);            final ViewGroup viewGroup = (ViewGroup) parent;            final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);            rInflate(parser, view, attrs, true);            viewGroup.addView(view, params);                        } else {            <!--創(chuàng)建View,如果有必要,接著遞歸-->            final View view = createViewFromTag(parent, name, attrs);            final ViewGroup viewGroup = (ViewGroup) parent;            final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);            rInflate(parser, view, attrs, true);            <!--添加View-->            viewGroup.addView(view, params);        }    }    if (finishInflate) parent.onFinishInflate();}

rInflate主要作用是開(kāi)啟遞歸遍歷,生成View樹(shù),createViewFromTag的主要作用是利用反射生成View對(duì)象,最終將View數(shù)顯示到屏幕上。biX28資訊網(wǎng)——每日最新資訊28at.com

biX28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-86982-0.htmlLayoutInflater的工作原理,從解析XML布局文件到創(chuàng)建Java對(duì)象,再到構(gòu)建View樹(shù)

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 基于Spring Boot 3.x與Flowable的順序會(huì)簽?zāi)J綄?shí)踐

下一篇: @Async注解失效的 9 種場(chǎng)景

標(biāo)簽:
  • 熱門(mén)焦點(diǎn)
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
狠狠久久亚洲欧美专区| 欧美电影电视剧在线观看| 99国产精品国产精品久久| 黑人巨大精品欧美一区二区| 国产亚洲日本欧美韩国| 国产一区二区| 一区在线观看| 国产亚洲免费的视频看| 在线播放日韩专区| 亚洲国产精品999| aa日韩免费精品视频一| 亚洲性夜色噜噜噜7777| 香蕉亚洲视频| 欧美一区二区免费视频| 久久先锋影音av| 欧美日韩国产一中文字不卡| 国产欧美日韩综合精品二区| 91久久国产综合久久| 亚洲一区二区三区午夜| 久久亚洲欧美| 国产精品久久午夜| 亚洲激情一区| 欧美一区二区三区视频| 欧美精品1区| 国内激情久久| 一区二区三区日韩精品| 久久婷婷久久| 99视频一区| 久久久99久久精品女同性| 欧美日韩国产综合一区二区| 国产亚洲免费的视频看| 亚洲美女色禁图| 久久精品一区| 国产精品久久午夜| 亚洲精品综合| 久久亚裔精品欧美| 国产精品一区二区久久| 亚洲日本在线观看| 久久久免费精品视频| 欧美性猛交xxxx乱大交蜜桃| 亚洲国产综合在线看不卡| 久久国产精品毛片| 欧美午夜在线| 亚洲日本欧美天堂| 久久久久久97三级| 国产欧亚日韩视频| 亚洲视频在线一区| 欧美高清在线一区| 黄色成人在线| 欧美一二三区在线观看| 国产精品vvv| 99国产精品| 欧美成人资源网| 一区二区三区自拍| 久久国产99| 国产精品区免费视频| 在线视频欧美精品| 欧美裸体一区二区三区| 黄色欧美日韩| 欧美有码在线视频| 国产精品日韩精品欧美精品| 一本综合久久| 欧美日韩成人| 亚洲伦理网站| 欧美激情成人在线视频| 在线免费观看日韩欧美| 久久久久久久综合| 国产一二三精品| 欧美一级专区| 国产日韩在线一区| 先锋资源久久| 国产精品一区久久久久| 午夜在线一区| 国产麻豆精品视频| 午夜在线视频观看日韩17c| 国产精品亚洲综合一区在线观看| 亚洲视频免费看| 国产精品久久7| 亚洲在线日韩| 国产精品美女久久久浪潮软件| 亚洲午夜未删减在线观看| 欧美性大战久久久久久久| 一区二区三区欧美亚洲| 国产精品jvid在线观看蜜臀| 亚洲综合国产| 国产伦精品一区二区三区照片91 | 亚洲成人在线免费| 久久男人av资源网站| 黄色成人av网站| 另类激情亚洲| 亚洲国产高清视频| 欧美激情1区2区| 亚洲美女电影在线| 欧美午夜大胆人体| 亚洲欧美国产视频| 国模一区二区三区| 理论片一区二区在线| 亚洲成色777777女色窝| 欧美福利一区二区三区| 亚洲日本久久| 欧美日韩一区二区在线| 亚洲欧美国产日韩中文字幕| 国产精品青草综合久久久久99 | 欧美色区777第一页| 亚洲午夜精品国产| 国产欧美日韩视频一区二区三区| 久久久精彩视频| 亚洲福利在线视频| 欧美日韩hd| 亚洲欧美日韩在线高清直播| 国产婷婷色一区二区三区四区 | 欧美日韩一区二区高清| 亚洲女性裸体视频| 国产香蕉久久精品综合网| 噜噜噜在线观看免费视频日韩| 亚洲精品色婷婷福利天堂| 欧美亚日韩国产aⅴ精品中极品| 午夜激情一区| 亚洲成人原创| 国产精品成人v| 久久精品久久99精品久久| 亚洲黄色一区| 国产精品综合| 牛牛精品成人免费视频| 一区二区三区波多野结衣在线观看| 国产精品中文在线| 欧美mv日韩mv亚洲| 亚洲小说春色综合另类电影| 韩国一区二区在线观看| 欧美精品久久久久久久免费观看 | 亚洲在线视频网站| 一色屋精品视频免费看| 欧美日韩一级片在线观看| 欧美一区国产二区| 亚洲理论电影网| 国产亚洲欧美另类一区二区三区| 欧美成人日本| 欧美一区二区三区四区夜夜大片 | 亚洲激情网站免费观看| 国产精品一区二区a| 欧美a级理论片| 午夜精品久久久久久99热软件| 亚洲国产精彩中文乱码av在线播放| 国产精品色一区二区三区| 欧美激情 亚洲a∨综合| 久久av最新网址| 国产精品99久久久久久白浆小说| 韩国三级在线一区| 国产精品99免费看 | 国产欧美日韩另类视频免费观看 | 国产精品大片| 女女同性精品视频| 欧美一级淫片aaaaaaa视频| 日韩特黄影片| 在线电影欧美日韩一区二区私密| 国产精品第一区| 欧美精品二区| 美国成人毛片| 久久经典综合| 亚洲欧美日韩综合aⅴ视频| 亚洲精品欧美精品| 伊人男人综合视频网| 国产嫩草影院久久久久| 欧美视频导航| 欧美精品激情在线观看| 久久永久免费| 羞羞答答国产精品www一本| 9色国产精品| 亚洲青色在线| 亚洲成色精品| 国产一区二区中文| 国产乱码精品一区二区三| 欧美日韩一区自拍| 欧美韩日一区二区三区| 久久一区精品| 久久精品在线| 欧美一区二区三区婷婷月色| 亚洲一区二区三区在线看| 亚洲毛片一区二区| 亚洲激情小视频| 亚洲电影在线观看| 黄色成人在线观看| 国内视频一区| 国产视频观看一区| 国产精一区二区三区| 国产精品日日做人人爱| 国产精品久久久久av| 国产精品久久久久99| 欧美午夜视频网站| 国产精品久久久久高潮| 国产精品激情偷乱一区二区∴| 欧美三级视频在线观看| 欧美日韩亚洲三区| 欧美日韩一区二区精品| 欧美日韩视频在线一区二区| 欧美人体xx| 欧美日韩国产123区| 欧美日韩成人一区二区三区| 欧美久久精品午夜青青大伊人| 欧美成人精品在线观看| 欧美精品三级日韩久久| 欧美激情视频一区二区三区免费 | 欧美日韩亚洲综合| 欧美日韩综合在线免费观看|