Android LayoutInflater from(@UiContext Context context)

LayoutInflater from(Context context) 流程
LayoutInflaterfromprocess

LayoutInflater from()流程图

  Android LayoutInflater from(@UiContext Context context)的代码如下:

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

  调用参数context的getSystemService()方法,得到实例LayoutInflater,然后将它返回。
  参数context一般都是Activity实例,所以看下Activity的getSystemService(),如下:

    @Override
    public Object getSystemService(@ServiceName @NonNull String name) {
        if (getBaseContext() == null) {
            throw new IllegalStateException(
                    "System services not available to Activities before onCreate()");
        }

        if (WINDOW_SERVICE.equals(name)) {
            return mWindowManager;
        } else if (SEARCH_SERVICE.equals(name)) {
            ensureSearchManager();
            return mSearchManager;
        }
        return super.getSystemService(name);
    }

  参数name目前是Context.LAYOUT_INFLATER_SERVICE,所以继续调用父类ContextThemeWrapper的getSystemService()方法,如下:

    @Override
    public Object getSystemService(String name) {
        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
            if (mInflater == null) {
                mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
            }
            return mInflater;
        }
        return getBaseContext().getSystemService(name);
    }

  这里找到对应的参数LAYOUT_INFLATER_SERVICE,当第一次调用该方法的时候,成员变量mInflater 是null,所以又调用了LayoutInflater.from()方法,不过注意了,参数不同了,参数是getBaseContext(),然后又调用了cloneInContext(this)方法,复制了一个。
  从上面还可以看到,Activity的getSystemService()方法,在参数为WINDOW_SERVICE、SEARCH_SERVICE、LAYOUT_INFLATER_SERVICE是进行的单独处理,为其他参数时,是调用的getBaseContext().getSystemService(name)。
  Activity的getBaseContext()得到的是它的成员变量mBase,看代码知,mBase也是Context类型,Activity也是Context类型。它俩有什么不同呢,其实,mBase是ContextImpl实例,Activity的Context类里的函数功能,都是通过mBase来实现的,这里是使用了代理模式。

ContextImpl的getSystemService()方法

  接着看下ContextImpl的getSystemService()方法,如下:

    @Override
    public Object getSystemService(String name) {
        if (vmIncorrectContextUseEnabled()) {
            // Check incorrect Context usage.
            if (WINDOW_SERVICE.equals(name) && !isUiContext()) {
                final String errorMessage = "Tried to access visual service "
                        + SystemServiceRegistry.getSystemServiceClassName(name)
                        + " from a non-visual Context:" + getOuterContext();
                final String message = "WindowManager should be accessed from Activity or other "
                        + "visual Context. Use an Activity or a Context created with "
                        + "Context#createWindowContext(int, Bundle), which are adjusted to "
                        + "the configuration and visual bounds of an area on screen.";
                final Exception exception = new IllegalAccessException(errorMessage);
                StrictMode.onIncorrectContextUsed(message, exception);
                Log.e(TAG, errorMessage + " " + message, exception);
            }
        }
        return SystemServiceRegistry.getSystemService(this, name);
    }

  调用了SystemServiceRegistry的getSystemService()方法,如下:

    /**
     * Gets a system service from a given context.
     * @hide
     */
    public static Object getSystemService(ContextImpl ctx, String name) {
        if (name == null) {
            return null;
        }
        final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        if (fetcher == null) {
            if (sEnableServiceNotFoundWtf) {
                Slog.wtf(TAG, "Unknown manager requested: " + name);
            }
            return null;
        }

        final Object ret = fetcher.getService(ctx);
        if (sEnableServiceNotFoundWtf && ret == null) {
            // Some services do return null in certain situations, so don't do WTF for them.
            switch (name) {
                case Context.CONTENT_CAPTURE_MANAGER_SERVICE:
                case Context.APP_PREDICTION_SERVICE:
                case Context.INCREMENTAL_SERVICE:
                case Context.ETHERNET_SERVICE:
                    return null;
            }
            Slog.wtf(TAG, "Manager wrapper not available: " + name);
            return null;
        }
        return ret;
    }

  SystemServiceRegistry的getSystemService()首先调用SYSTEM_SERVICE_FETCHERS.get(name)得到ServiceFetcher实例fetcher ,然后调用fetcher 的getService()方法,再得到具体的结果实例,最后将结果返回,这就是最终的LayoutInflater实例。
  SYSTEM_SERVICE_FETCHERS是ArrayMap<String, ServiceFetcher<?>>类型,通过key值得到value,value类型是ServiceFetcher。那在这个ArrayMap里面,什么时候开始注册它的呢。
  再看下ServiceFetcher类的getService(ContextImpl ctx)方法,

    static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }

  ServiceFetcher是一个接口,对于LayoutInflater来说,在SYSTEM_SERVICE_FETCHERS得到的fetcher是CachedServiceFetcher类型,后面再分析它的getService(ContextImpl ctx)实现

LayoutInflater在SYSTEM_SERVICE_FETCHERS中注册

  它的相关注册,是在SystemServiceRegistry的static代码块中,只要开始加载SystemServiceRegistry类,就会执行。看下相关代码:

    static {
        //CHECKSTYLE:OFF IndentationCheck
        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());
            }});     
            …………
            …………
        registerService(Context.DISPLAY_HASH_SERVICE, DisplayHashManager.class,
                new CachedServiceFetcher<DisplayHashManager>() {
                    @Override
                    public DisplayHashManager createService(ContextImpl ctx) {
                        return new DisplayHashManager();
                    }});

            …………
            …………
    }       

  静态初始化块中,注册了好多相关的ServiceFetcher,均是通过registerService()方法。主要看与LAYOUT_INFLATER_SERVICE相关的。看下registerService()方法:

    /**
     * Statically registers a system service with the context.
     * This method must be called during static initialization only.
     */
    private static <T> void registerService(@NonNull String serviceName,
            @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
        SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
    }

  SystemServiceRegistry类的静态成员SYSTEM_SERVICE_NAMES是ArrayMap<Class<?>, String>类型,可以通过Class得到对应的注册服务对应的名称;SYSTEM_SERVICE_FETCHERS是 ArrayMap<String, ServiceFetcher<?>>类型,可以通过注册的名称得到对应的ServiceFetcher实例;SYSTEM_SERVICE_CLASS_NAMES是ArrayMap<String, String>类型,可以通过注册的名称得到对应的类的名称。
  对于LayoutInflater,在这里可以看到注册的对应的ServiceFetcher具体是CachedServiceFetcher类型。

CachedServiceFetcher的getService(ContextImpl ctx)

  分段看一下,第一段代码:

        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            final int[] gates = ctx.mServiceInitializationStateArray;
            boolean interrupted = false;

            T ret = null;

  首先取得参数ctx的成员变量mServiceCache,它的赋值mServiceCache = SystemServiceRegistry.createServiceCache()。而SystemServiceRegistry的createServiceCache():

    public static Object[] createServiceCache() {
        return new Object[sServiceCacheSize];
    }

  它每次都生成一个新Object数组,大小是sServiceCacheSize。这个大小,是上面讲述的每次调用registerService()函数,生成CachedServiceFetcher实例的时候,会将sServiceCacheSize加1。它就是注册的CachedServiceFetcher实例的个数。
  接着getService(ContextImpl ctx)调用ctx.mServiceInitializationStateArray得到int 数组gates。它的大小是和得到的数组cache 大小相等。
  继续初始化interrupted 为false,ret为null
  下面看第二段代码:

            for (;;) {
                boolean doInitialize = false;
                synchronized (cache) {
                    // Return it if we already have a cached instance.
                    T service = (T) cache[mCacheIndex];
                    if (service != null) {
                        ret = service;
                        break; // exit the for (;;)
                    }

                    // If we get here, there's no cached instance.

                    // Grr... if gate is STATE_READY, then this means we initialized the service
                    // once but someone cleared it.
                    // We start over from STATE_UNINITIALIZED.
                    // Similarly, if the previous attempt returned null, we'll retry again.
                    if (gates[mCacheIndex] == ContextImpl.STATE_READY
                            || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
                        gates[mCacheIndex] = ContextImpl.STATE_UNINITIALIZED;
                    }

                    // It's possible for multiple threads to get here at the same time, so
                    // use the "gate" to make sure only the first thread will call createService().

                    // At this point, the gate must be either UNINITIALIZED or INITIALIZING.
                    if (gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED) {
                        doInitialize = true;
                        gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING;
                    }
                }

  进入了一个for循环中,声明一个值为false的doInitialize,接着获取到变量cache的锁,然后去cache中看是否已经存在一个缓存了。如果存在就会,将缓存结果返回了。
  cache的锁在这里是用来,避免多线程情况下,gates[mCacheIndex]值设置错乱。gates是一个int数组,gates[mCacheIndex]在这里用来表示ContextImpl对应的当前服务实例生成过程走到了哪个步骤,初始的状态就是ContextImpl.STATE_UNINITIALIZED。ContextImpl.STATE_READY 表示之前成功生成过相应的服务,在LayoutInflater 这,就对应生成过LayoutInflater 实例,并且已缓存;ContextImpl.STATE_NOT_FOUND 表示之前生成相应服务的时候,没找到对应的服务。
  如果gates[mCacheIndex]的值是ContextImpl.STATE_READY,则代表生成的缓存被清理了。在gates[mCacheIndex]的值是ContextImpl.STATE_READY或者ContextImpl.STATE_NOT_FOUND的情况下,先将gates[mCacheIndex] = ContextImpl.STATE_UNINITIALIZED。需要重新生成一个。
  代码接着判断如果gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED,会将doInitialize = true,gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING。doInitialize = true,代表已经初始化过了,并且是通过它来实现多线程竞争状态下,只能由单个线程来执行createService()生成服务。gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING,代表正在执行createService()的过程中。gates[mCacheIndex] 为 ContextImpl.STATE_INITIALIZING,还能避免线程在执行createService()的过程中,其他的线程代码走到判断 gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED的时候,将doInitialize = true,导致多个线程执行createService()生成服务。
  接着看第三段代码:

                if (doInitialize) {
                    // Only the first thread gets here.

                    T service = null;
                    @ServiceInitializationState int newState = ContextImpl.STATE_NOT_FOUND;
                    try {
                        // This thread is the first one to get here. Instantiate the service
                        // *without* the cache lock held.
                        service = createService(ctx);
                        newState = ContextImpl.STATE_READY;

                    } catch (ServiceNotFoundException e) {
                        onServiceNotFound(e);

                    } finally {
                        synchronized (cache) {
                            cache[mCacheIndex] = service;
                            gates[mCacheIndex] = newState;
                            cache.notifyAll();
                        }
                    }
                    ret = service;
                    break; // exit the for (;;)
                }

  先判断doInitialize,然后调用了createService(ctx)来生成服务。createService(ctx)成功之后,会将状态设置成ContextImpl.STATE_READY。如果发生异常,状态会是ContextImpl.STATE_NOT_FOUND。最后会在finally代码中,将生成的服务service缓存起来,状态也设置到gates[mCacheIndex]中。可知,这个值可能是ContextImpl.STATE_READY,也可能是ContextImpl.STATE_NOT_FOUND。
  finally 代码中,还用synchronized 加锁,并且会调用cache.notifyAll(),来唤醒在该锁上等待的线程,这个等会从下面的代码看出等待锁的线程。
  生成服务之后,将它赋值给ret,跳出for循环。

createService() 生成服务

  createService()的实现是在注册那块,看一下:

			public LayoutInflater createService(ContextImpl ctx) {
                return new PhoneLayoutInflater(ctx.getOuterContext());
            }

  直接生成了一个PhoneLayoutInflater对象,所以通过LayoutInflater from(Context context)得到的是一个PhoneLayoutInflater实例。它的参数是ContextImpl 类对象的getOuterContext(),它指向一个Activity实例。
  接着看getService()的第四段代码:

                synchronized (cache) {
                    while (gates[mCacheIndex] < ContextImpl.STATE_READY) {
                        try {
                            // Clear the interrupt state.
                            interrupted |= Thread.interrupted();
                            cache.wait();
                        } catch (InterruptedException e) {
                            // This shouldn't normally happen, but if someone interrupts the
                            // thread, it will.
                            Slog.w(TAG, "getService() interrupted");
                            interrupted = true;
                        }
                    }
                }
            }
            if (interrupted) {
                Thread.currentThread().interrupt();
            }
            return ret;
        }

  synchronized (cache)这个锁,是为了处理多线程的。如果多个线程同时调用同一个Activity的LayoutInflater.from(Context context),就可能出现多个线程同时访问getService()。但是只会1个线程去执行createService(),生成成功,再放入缓存中。其他的线程可能会走到这块加锁的代码中,然后判断gates[mCacheIndex]的值为ContextImpl.STATE_INITIALIZING,小于ContextImpl.STATE_READY,所以通过cache.wait(),等待createService()完成。
  第三段代码中,咱们分析了,在createService()完成之后,会调用cache.notifyAll()来唤醒在该锁上等待的线程。线程唤醒之后,还会通过while循环去判断,这个时候,gates[mCacheIndex]的值已经是ContextImpl.STATE_READY或ContextImpl.STATE_NOT_FOUND,不满足循环的条件,会跳出while循环。接着又会进入for循环中,这个时候再从缓存中获取的,就能获取到值了。
  最后就是将结果ret返回。

PhoneLayoutInflater类的cloneInContext(Context newContext)

  在前面ContextThemeWrapper的getSystemService()里调用LayoutInflater.from(getBaseContext())返回结果LayoutInflater类实例之后,还会调用LayoutInflater类实例的cloneInContext(Context newContext)方法,然后再将结果返回。而这个LayoutInflater类实例从上面的分析知道,它实际是一个PhoneLayoutInflater实例。
  看一下PhoneLayoutInflater类的cloneInContext(Context newContext):

		public LayoutInflater cloneInContext(Context newContext) {
        return new PhoneLayoutInflater(this, newContext);
    }
    
    protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
        super(original, newContext);
    }

  接着又调用LayoutInflater 类的构造函数:

    protected LayoutInflater(LayoutInflater original, Context newContext) {
        StrictMode.assertConfigurationContext(newContext, "LayoutInflater");
        mContext = newContext;
        mFactory = original.mFactory;
        mFactory2 = original.mFactory2;
        mPrivateFactory = original.mPrivateFactory;
        setFilter(original.mFilter);
        initPrecompiledViews();
    }

  这块主要是新生成一个PhoneLayoutInflater类对象,将新对象的成员变量mContext 指向cloneInContext(Context newContext)方法参数里的newContext 。PhoneLayoutInflater类对象没设置mFactory,mFactory2、mPrivateFactory、mFilter。

  分析完这些代码之后,我们发现其主要就是通过加锁机制,然后通过new PhoneLayoutInflater(),得到了一个PhoneLayoutInflater实例。为啥,要整的像上面这样似的还先注册,然后设计接口,再实现,整的挺复杂。其实不止LayoutInflater实例,是这样实现的。像其他的ActivityManager、ActivityTaskManager、AccessibilityManager等实例都是通过类似这样的一种方式实现的。这样就通过设计形式,将这些实例的获取方式统一了起来。这也是值得我们学习的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值