美文网首页
从 LayoutInflater 看 Android 中的单例模

从 LayoutInflater 看 Android 中的单例模

作者: stefanJi | 来源:发表于2018-07-21 15:40 被阅读0次

经常使用 Context.getSystemService(String name) 获取一些系统服务。 其实这些服务都是以单例的方式注册在系统中的。 获取到的都是单例对象。

LayoutInflater 为例

在 View 中经常通过 LayoutInflater.from(Context context) 获取 LayoutInflater 对象,查看方法实现:

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

内部是调用的 Context 的 getSystemService(String key) 方法,查看 Context 类发现是个抽象方法,需要子类实现:

public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);

View 中的 Context 通常就是 Activity,Android 中在 Application,Activity,Service 中都存在 Context。一个应用中: Context 总数 = Activity 数 + Service 数 + 1 ( Application )。

所以从 Activity 的 Context 中分析 getSystemService 实现,先分析 Activity 的 Context 是在哪创建的。

Activity 的入口是 ActivityThread 的 main 函数:

public static void main(String[] args) {
    ...
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    if (false) {
        Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
    }
    ...
    Looper.loop();
    
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

创建 MainLooper,创建 ActivityThread 对象 ,启动 Looper 消息循环。ActivityThread 的 attach 方法:

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
    ......
}

不是系统应用(boolean system)会通过 Binder 机制与 ActivityManagerService 通信,最终调用 handleLaunchActivity,里面又会调用 performLaunchActivity 方法:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    ActivityInfo aInfo = r.activityInfo;
    ...
    ContextImpl appContext = createBaseContextForActivity(r);
    ...
    activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
    ...
}

ActivityThread createBaseContextForActivity 方法:

private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
    final int displayId;
    try {
        displayId = ActivityManager.getService().getActivityDisplayId(r.token);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
    ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
    ...
}

performLaunchActivity 里创建了 ContextImpl 对象,Context 的具体实现就是 ComtextImpl 了。查看 ContextImpl 里 getSystemService 实现:

public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}

ContextImpl 里通过 SystemServiceRegistry 的类方法获取服务,查看 SystemServiceRegistry 类:

final class SystemServiceRegistry {
    private static final String TAG = "SystemServiceRegistry";

    // Service registry information.
    // This information is never changed once static initialization has completed.
    private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
            new HashMap<Class<?>, String>();
    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();
    private static int sServiceCacheSize;

    private SystemServiceRegistry() { }

    // 静态代码块,类加载时就执行
    static {
        registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
                new CachedServiceFetcher<AccessibilityManager>() {
            @Override
            public AccessibilityManager createService(ContextImpl ctx) {
                return AccessibilityManager.getInstance(ctx);
            }});

        registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
                new CachedServiceFetcher<LayoutInflater>() {
            @Override
            public LayoutInflater createService(ContextImpl ctx) {
                return new PhoneLayoutInflater(ctx.getOuterContext());
            }});
        ...
    }

    // 获取服务
    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }
}

静态代码块里注册了很多服务, LayoutInflater 也是在这里注册的, 看到 LayoutInflater 的实现类是 PhoneLayoutInflater

PhoneLayoutInflater

获得了 LayoutInflater 之后,就该调用 inflate 加载,查看源码:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
    final Resources res = getContext().getResources();
    if (DEBUG) {
        Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                + Integer.toHexString(resource) + ")");
    }

    final XmlResourceParser parser = res.getLayout(resource);
    try {
        return inflate(parser, root, attachToRoot);
    } finally {
        parser.close();
    }
}

继续查看:

    public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            final Context inflaterContext = mContext;
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            Context lastContext = (Context) mConstructorArgs[0];
            mConstructorArgs[0] = inflaterContext;
            View result = root;

            try {
                // 查找根节点
                int type;
                while ((type = parser.next()) != XmlPullParser.START_TAG &&
                        type != XmlPullParser.END_DOCUMENT) {
                    // Empty
                }
                final String name = parser.getName();
                // 解析 merge 标签
                if (TAG_MERGE.equals(name)) {                    
                    rInflate(parser, root, inflaterContext, attrs, false);
                } else {
                    // 从 xml 中构造 View
                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                    ViewGroup.LayoutParams params = null;
                    ...                    
                    if (root != null && attachToRoot) {
                        root.addView(temp, params);
                    }
                    if (root == null || !attachToRoot) {
                        result = temp;
                    }
                    ...
                    rInflateChildren(parser, temp, attrs, true);
                    ...
                }

            }
            ...
            return result;
        }
    }

调用 createViewFromTag :

View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
            boolean ignoreThemeAttr) {
        if (name.equals("view")) {
            name = attrs.getAttributeValue(null, "class");
        }
        ...
        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;
        ...
}
  • 解析内置控件:调用 onCreateView
  • 解析自定义控件:直接调用 createView(name, null, attrs);

前面分析了,Activity 的 Context 返回的 LayoutInflater 对象的具体实现是 PhoneLayoutInflater,查看源码,发现其复写了 onCreateView 方法:

public class PhoneLayoutInflater extends LayoutInflater {
    private static final String[] sClassPrefixList = {
        "android.widget.",
        "android.webkit.",
        "android.app."
    };
    ...
    /** Override onCreateView to instantiate names that correspond to the
        widgets known to the Widget factory. If we don't find a match,
        call through to our super class.
        复写 LayoutInflater 的 onCreateView
    */
    @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
        for (String prefix : sClassPrefixList) {
            try {
                View view = createView(name, prefix, attrs);
                if (view != null) {
                    return view;
                }
            } catch (ClassNotFoundException e) {
                // In this case we want to let the base class take a crack
                // at it.
            }
        }

        return super.onCreateView(name, attrs);
    }
}

所以,在 PhoneLayoutInflater 解析内置控件时,会使用3种前缀。

createView 在 LayoutInflater 中实现:

public final View createView(String name, String prefix, AttributeSet attrs)
        throws ClassNotFoundException, InflateException {
    //先根据类名从缓存中获取构造器
    Constructor<? extends View> constructor = sConstructorMap.get(name);
    if (constructor != null && !verifyClassLoader(constructor)) {
        constructor = null;
        sConstructorMap.remove(name);
    }
    Class<? extends View> clazz = null;
    try {
        // 如果构造函数不存在,就通过反射获取构造函数
        if (constructor == null) {            
            clazz = mContext.getClassLoader().loadClass(
                    prefix != null ? (prefix + name) : name).asSubclass(View.class);
            if (mFilter != null && clazz != null) {
                boolean allowed = mFilter.onLoadClass(clazz);
                if (!allowed) {
                    failNotAllowed(name, prefix, attrs);
                }
            }
            constructor = clazz.getConstructor(mConstructorSignature);
            constructor.setAccessible(true);
            sConstructorMap.put(name, constructor);
        }
    }
    ...
    //构造View
    final View view = constructor.newInstance(args);
    if (view instanceof ViewStub) {        
        final ViewStub viewStub = (ViewStub) view;
        viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
    }    
    return view;
}        

这样就成功从 xml 构造了一个根 View,接着就会调用 rInflateChildren 创建子 View。 rInflateChildren 调用 rInflate

void rInflate(XmlPullParser parser, View parent, Context context,
            AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
    //获得布局深度
    final int depth = parser.getDepth();
    int type;
    boolean pendingRequestFocus = false;
    
    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();
        //requestFocus 标签
        if (TAG_REQUEST_FOCUS.equals(name)) {
            pendingRequestFocus = true;
            consumeChildElements(parser);
        //tag 标签
        } else if (TAG_TAG.equals(name)) {
            parseViewTag(parser, parent, attrs);
        //include 标签
        } else if (TAG_INCLUDE.equals(name)) {
            if (parser.getDepth() == 0) {
                throw new InflateException("<include /> cannot be the root element");
            }
            parseInclude(parser, context, parent, attrs);
        //merge 标签
        } else if (TAG_MERGE.equals(name)) {
            throw new InflateException("<merge /> must be the root element");
        //普通 View 标签
        } else {
            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);
        }
    }
    if (pendingRequestFocus) {
        parent.restoreDefaultFocus();
    }
    if (finishInflate) {
        parent.onFinishInflate();
    }
}

相关文章

网友评论

      本文标题:从 LayoutInflater 看 Android 中的单例模

      本文链接:https://www.haomeiwen.com/subject/qymhmftx.html