1. 程式人生 > >Android Context getSystemService分析

Android Context getSystemService分析

我們知道一個應用的Context個數是Activity個數+Service個數+1

當我們希望獲取到系統服務時,可以呼叫Context的getSystemService方法,如獲取到ActivityManager:

ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);

那麼getSystemService又是怎麼工作的呢?

Activity是一個Context,他呼叫getSystemService時,會呼叫到Context的包裝類ContextWrapper的getSystemService方法,如下:

@Override
public Object getSystemService(String name) {
    return mBase.getSystemService(name);
}

mBase是Context的實現類ContextImpl,很明顯ContextWrapper又會委託ContextImpl去實現具體邏輯。

我們跟進ContextImpl中的getSystemService方法,如下:

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

其內部是呼叫了SystemServiceRegistry的getSystemService方法,這時獲取系統服務的過程就轉移到了SystemServiceRegistry了。

我們看到SystemServiceRegistry的getSystemService方法即可,如下:

/**
 * 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.get(name)是什麼?

SYSTEM_SERVICE_FETCHERS是一個儲存ServiceFetcher的HashMap

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

我們先不管SYSTEM_SERVICE_FETCHERS.get(name)返回值是什麼,

先發現ServiceFetcher是什麼時候儲存到SYSTEM_SERVICE_FETCHERS裡的。

SystemServiceRegistry中有一段靜態程式碼塊長這樣:

static {

     //程式碼省略

registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
            new CachedServiceFetcher<ActivityManager>() {
        @Override
        public ActivityManager createService(ContextImpl ctx) {
            return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
        }});

    registerService(Context.ALARM_SERVICE, AlarmManager.class,
            new CachedServiceFetcher<AlarmManager>() {
        @Override
        public AlarmManager createService(ContextImpl ctx) {
            IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
            IAlarmManager service = IAlarmManager.Stub.asInterface(b);
            return new AlarmManager(service, ctx);
        }});

     //程式碼省略
}

靜態程式碼塊只在虛擬機器第一次載入類的時候執行。

靜態程式碼塊中呼叫registerService方法來註冊系統服務的,而registerService方法內部是將key和value存進去SYSTEM_SERVICE_FETCHERS,找到了,如下:

/**
 * 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);
}

可以看到存進了serviceFetcher,而serviceName就是我們傳進的字串,比如
Context.ACTIVITY_SERVICE

我們分析ActivityManager即可,在註冊ActivityManager時傳進registerService方法的是CachedServiceFetcher,那麼我們跟進CachedServiceFetcher看看。

/**
 * 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) {
                service = createService(ctx);
                cache[mCacheIndex] = service;
            }
            return (T)service;
        }
    }

    public abstract T createService(ContextImpl ctx);
}

CachedServiceFetcher實現了ServiceFetcher介面,這個getService方法是在一開始的getSystemService方法中觸發,如下

return fetcher != null ? fetcher.getService(ctx) : null;

喔,原來是通過ServiceFetcher來獲取系統服務的。

到這裡我們分析CachedServiceFetcher可以知道,當第一次獲取服務的時候,會呼叫createService去建立例項,然後將服務物件新增進快取。下次再取時就直接從快取中獲取了。其實這是一種使用容器來實現的單例模式。

最後總結一下:當我們呼叫Context的getSystemService方法獲取服務時,會轉到SystemServiceRegistry類的getSystemService方法,在這個getSystemService方法中,根據key,也就是我們傳入的字串,比如Context.ACTIVITY_SERVICE。根據傳入的key從SYSTEM_SERVICE_FETCHERS這個HashMap中獲取到ServiceFetcher例項,再呼叫ServiceFetcher例項的getService方法獲取到系統服務物件。如果是第一次獲取系統服務的話,會呼叫ServiceFetcher的createService方法去建立系統服務例項並將其加入快取列表,之後再次獲取就是從快取中取出了。

而靜態程式碼塊又是怎麼回事?其實就是為每一個系統服務執行了以下的程式碼嘛

SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);

SystemServiceRegistry中的靜態程式碼塊只會執行一次,告訴系統,我是有這些服務的,將一些key和value新增進HashMap。就是一些初始化的工作。而並沒有真正去建立系統服務物件,因為createService還沒有被呼叫啊

好了,以上就是Context的getSystemService方法的工作過程分析。從中我學到了原來還有這種使用容器的單例模式。