Android LayoutInflater和findViewById 源碼詳解


LayoutInflater大家很熟悉,簡單點說就是布局文件XML解析器,setContentView函數也是調用了LayoutInflater

用法:
View view = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
LayoutInflater lyInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
上面的用法本質上都是一樣.

 

控制台打印 重復調用LayoutInflater.from(this)  同一個進程下面 實例是單例
com.android.internal.policy.impl.PhoneLayoutInflater@420dcf80
com.android.internal.policy.impl.PhoneLayoutInflater@420dcf80
com.android.internal.policy.impl.PhoneLayoutInflater@420dcf80

   首先 LayoutInflater 是一個抽象類,實例化對象是從Service取出的。但是並沒有到底層Binder去實例化對象。最終實例對象是PhoneLayoutInflater類

    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;
    }

  

    從Activity父類可以找到 getSystemService方法
    public Object getSystemService(String name) {
        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
            if (mInflater == null) {
                mInflater = LayoutInflater.from(mBase).cloneInContext(this); //在這個地方實例化的,主要關聯到mBase Context對象實例
            }
            return mInflater;
        }
        return mBase.getSystemService(name);
    }

 

    重點是Context的實例化對象 有個子類 ContextImpl.java 里面注冊了相關Service
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }

 

    SYSTEM_SERVICE_MAP 是個hashMap  注冊的服務都存在這個地方,對象被緩存。
    private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>();
    
    abstract static class StaticServiceFetcher extends ServiceFetcher {
        private Object mCachedInstance;

        @Override
        public final Object getService(ContextImpl unused) {
            synchronized (StaticServiceFetcher.this) {
                Object service = mCachedInstance;
                if (service != null) {
                    return service;
                }
                return mCachedInstance = createStaticService();
            }
        }
        public abstract Object createStaticService(); //這個用於創建static服務
    }
    
    registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() { //創建獨立的對象 用於LayoutInflater
        public Object createService(ContextImpl ctx) {
           return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
    }});

 

 

 

    /*package*/ static class ServiceFetcher {
        int mContextCacheIndex = -1;

        /**
         * Main entrypoint; only override if you don't need caching.
         */
        public Object getService(ContextImpl ctx) {// ContextImpl實例。
            ArrayList<Object> cache = ctx.mServiceCache;
            Object service;
            synchronized (cache) {
                if (cache.size() == 0) {
                    // Initialize the cache vector on first access.
                    // At this point sNextPerContextServiceCacheIndex
                    // is the number of potential services that are
                    // cached per-Context.
                    for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
                        cache.add(null);
                    }
                } else {
                    service = cache.get(mContextCacheIndex);//獲取緩存是否存在
                    if (service != null) {
                        return service;
                    }
                }
                service = createService(ctx); //用來緩存服務實例
                cache.set(mContextCacheIndex, service);
                return service;
            }
        }

        /**
         * Override this to create a new per-Context instance of the
         * service.  getService() will handle locking and caching.
         */
        public Object createService(ContextImpl ctx) {
            throw new RuntimeException("Not implemented");
        }
    }

 

 

    com.android.internal.policy.PolicyManager
    找到了LayoutInflater的實現類
    
    這個類算是個代理類 本質上是 
    private static final String POLICY_IMPL_CLASS_NAME =
        "com.android.internal.policy.impl.Policy";
    
    policy\src\com\android\internal\policy\impl 目錄下
    
    
    public LayoutInflater makeNewLayoutInflater(Context context) {
        return new PhoneLayoutInflater(context); //實例化
    }
    
    
    policy\src\com\android\internal\policy\impl\PhoneLayoutInflater
    
    回到LayoutInflater 遞歸解析XML 使用的是XMl Pull Parser解析器
    
    public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
    
    }

 

    rInflate開始遞歸 都是XML解析
    
    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)) {
                if (parser.getDepth() == 0) {
                    throw new InflateException("<include /> cannot be the root element");
                }
                parseInclude(parser, parent, attrs);
            } else if (TAG_MERGE.equals(name)) {
                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 {
                final View view = createViewFromTag(parent, name, attrs);
                final ViewGroup viewGroup = (ViewGroup) parent;
                final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
                rInflate(parser, view, attrs, true);
                viewGroup.addView(view, params);
            }
        }

        if (finishInflate) parent.onFinishInflate();//解析完了,這個方法我們自定義可以復寫 可以會去掉 子View的信息
    }

 

基本上布局都是ViewGroup的子類 里面都有child view, 我們常用的findViewById 就是遍歷去找對應ID的View
    public final View findViewById(int id) {
        if (id < 0) {
            return null;
        }
        return findViewTraversal(id);
    }
    直接看ViewGroup中的findViewTraversal
    
    @Override
    protected View findViewTraversal(int id) { 
        if (id == mID) { //等於自己
            return this;
        }

        final View[] where = mChildren;
        final int len = mChildrenCount;

        for (int i = 0; i < len; i++) {
            View v = where[i];

            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) { //IS_ROOT_NAMESPACE 可能是查詢到最后一層了(猜的)  然后再遍歷 查詢
                v = v.findViewById(id);

                if (v != null) {
                    return v;
                }
            }
        }

        return null;
    }

 

如果布局層級太深 解析XML和查找View都是耗費CPU的,所以做項目過程中 有必要進行布局優化。

本文源碼: 4.1

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM