单例模式-LayoutInflater

前言

在Android系统中,我们通常会通过上下文对象Context获取一些系统级别的服务。而这些服务会在适当的时候以单例的形式注册在系统中,那么我们就可以通过Context的getSystemService(String name)获取。

以下的源码是Android8.0 API 26。

LayoutInflater

今天我们来看一下Android源码中的设计模式之单例模式。我们来讲一讲我们经常用到的单例类LayoutInflater。在我们使用RecylerView时,经常会用到,我们写RecyclerView的适配器时就会用到,如:

public class RvAdapter extends RecyclerView.Adapter<RvViewHolder> {
    ...
    @NonNull
    @Override
    public RvViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_item,parent,false);
        return new RvViewHolder(itemView);
    }
    ...
}

我们使用LayoutInflater.from(parent.getContext())来获取我们的LayoutInflater服务。我们来看看LayoutInflater的from方法:

/**
 * Obtains the LayoutInflater from the given context.
 */
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已在某个时刻以单例的形式注册在系统中了。我们现在通过上下文对象Context去获取这个对象。那么我们去看看Context对象的getSystemService方法是如何获取系统服务的:

/**
 * Interface to global information about an application environment.  This is
 * an abstract class whose implementation is provided by
 * the Android system.  It
 * allows access to application-specific resources and classes, as well as
 * up-calls for application-level operations such as launching activities,
 * broadcasting and receiving intents, etc.
 */
public abstract class Context {
  public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);

    /**
     * Return the handle to a system-level service by class.
     * <p>
     * Currently available classes are:
     * {@link android.view.LayoutInflater}
     * ...
     */
}

从上面的信息,我们可以知道Context是一个抽象类,它的实现是由Android系统提供的。Context提供了关于应用环境的全局信息的接口,即我们可以通过Context提供的接口获取关于应用的全局信息。我们看看Android系统对Context的实现,如果想知道Context的实现类,我们就要找到Context在哪里被初始化,我们可以从Activity的初始化开始查找,一个Activity的入口是ActivityThread的main函数:
ActivityThread对象管理应用进程的主线程的执行,如计划和执行activity、广播和其他activity管理者请求的操作。

/**
 * This manages the execution of the main thread in an
 * application process, scheduling and executing activities,
 * broadcasts, and other operations on it as the activity
 * manager requests.
 *
 * {@hide}
 */
public final class ActivityThread extends ClientTransactionHandler {
public static void main(String[] args) {
       ...
    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.
     * 将当前线程初始化为一个循环,作为应用程序的主循环,这个主循环是Android环境创建,我
     * 们不能亲自去调用这个prepareMainLooper方法
     */
       Looper.prepareMainLooper();
       ...
       /**
        * 创建ActivityThread对象
        */
       ActivityThread thread = new ActivityThread();
       thread.attach(false);
       ...

		/**
		* 初始化主线程的Handler
		*/
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        ...
    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     * 在这个线程运行消息队列
     */
        Looper.loop();
        ...

    }

}

我再来看看thread.attach()这个方法:

private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            // Watch for getting close to heap limit.
            // 监视是否接近堆的限制
            BinderInternal.addGcWatcher(new Runnable() {
                @Override public void run() {
                    if (!mSomeActivitiesChanged) {
                        return;
                    }
                    Runtime runtime = Runtime.getRuntime();
                    long dalvikMax = runtime.maxMemory();
                    long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                    if (dalvikUsed > ((3*dalvikMax)/4)) {
                        if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                                + " total=" + (runtime.totalMemory()/1024)
                                + " used=" + (dalvikUsed/1024));
                        mSomeActivitiesChanged = false;
                        try {
                            mgr.releaseSomeActivities(mAppThread);
                        } catch (RemoteException e) {
                            throw e.rethrowFromSystemServer();
                        }
                    }
                }
            });
        } else {
            // Don't set application object here -- if the system crashes,
            // we can't display an alert, we just want to die die die.
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }

        // add dropbox logging to libcore
        DropBox.setReporter(new DropBoxReporter());

        ViewRootImpl.ConfigChangedCallback configChangedCallback
                = (Configuration globalConfig) -> {
            synchronized (mResourcesManager) {
                // We need to apply this change to the resources immediately, because upon returning
                // the view hierarchy will be informed about it.
                if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
                        null /* compat */)) {
                    updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                            mResourcesManager.getConfiguration().getLocales());

                    // This actually changed the resources! Tell everyone about it.
                    if (mPendingConfiguration == null
                            || mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
                        mPendingConfiguration = globalConfig;
                        sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
                    }
                }
            }
        };
        ViewRootImpl.addConfigCallback(configChangedCallback);
    }
 }

从上面的代码我们看到Context的实现类,可能是ContextImpl,我们来看看ContextImpl.java:
ContextImpl为Context API的一般实现,它为Activity和其他应用组件提供了基本的上下文对象。

/**
 * Common implementation of Context API, which provides the base
 * context object for Activity and other application components.
 */
class ContextImpl extends Context {
	...
    @Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }
    ...
}

SystemServiceRegistry类管理所有系统服务,可以通过Context对象的getSystemService方法获得服务。

/**
 * Manages all of the system services that can be returned by {@link Context#getSystemService}.
 * Used by {@link ContextImpl}.
 */
final class SystemServiceRegistry {
	...
   /**
     * Gets a system service from a given context.
     */
    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }
    ...
}

SYSTEM_SERVICE_FETCHERS是一个HashMap:

private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();

SystemServiceRegistry还有一段这样的代码:

 /**
     * Base interface for classes that fetch services.
     * These objects must only be created during static initialization.
     */
    static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }

    /**
     * Override this class when the system service constructor needs a
     * ContextImpl and should be cached and retained by that context.
     */
    static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
        private final int mCacheIndex;

        public CachedServiceFetcher() {
            mCacheIndex = sServiceCacheSize++;
        }

        @Override
        @SuppressWarnings("unchecked")
        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            synchronized (cache) {
                // Fetch or create the service.
                Object service = cache[mCacheIndex];
                if (service == null) {
                    try {
                        service = createService(ctx);
                        cache[mCacheIndex] = service;
                    } catch (ServiceNotFoundException e) {
                        onServiceNotFound(e);
                    }
                }
                return (T)service;
            }
        }

        public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;
    }

CachedServiceFetcher的mCacheIndex会保存单例在数组中的位置,数组的初始化也就是单例的初始化是在下面这个静态代码块里完成。
SystemServiceRegistry有一个静态块:

 static {
        // 注册各种各样的服务,都是单例
        ...
        registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
                new CachedServiceFetcher<LayoutInflater>() {
            @Override
            public LayoutInflater createService(ContextImpl ctx) {
                return new PhoneLayoutInflater(ctx.getOuterContext());
            }});
            ...
    }
    /**
     * Statically registers a system service with the context.
     * This method must be called during static initialization only.
     */
    private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }

至此,我们终于从SystemServiceRegistry对象中把LayoutInflater单例取回来了。
核心服务以单例形式存在,减少了资源的消耗。

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值