【Android】 context.getSystemService()淺析


同事在進行code review的時候問到我context中的getSystemService方法在哪實現的,他看到了一個ClipBoardManager來進行剪切板存儲數據的工具方法中用到了context.getSystemService(),而此處我使用的是Application級別的Context進行調用的,可IDE跳轉時發現當前類中的getSystemService()方法居然是抽象的,Context類就是一個抽象類,沒有具體的實現,可在進行調用的時候卻一切正常,同事好奇該方法具體實現在哪實現的,於是我倆一起看源碼和查資料后發現有幾個值得注意的地方:

  • 系統service獲取和分享的問題,源碼中提示到:

Note:  System services obtained via this API may be closely associated with the Context in which they are obtained from.  In general, do not share the service objects between various different contexts (Activities, Applications, Services, Providers, etc.)

大意: 獲取的系統service可能和他們的context有緊密聯系,一般來說不要在不同的context之間分享服務對象,如Activity、Application、Service、Provider

明顯同樣的方法調用的具體實現不同,從同樣擁有getSystemService的Activity的實現可以看到,雖然最終調用還是從LayoutInflater的context獲取

/*
 * 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;
    }
  	// 以上的判斷僅僅是為了檢查是否為WindowManager獲取窗口的服務
    return super.getSystemService(name);
}

通過super.getSystemService(name)跳轉到ContextThemeWrapper這個Context.java類的代理類中,然而也並非是真正的具體實現,但是在此我們可以得知LayoutInflater實際上也是獲取的是Application級別的全局context,因為該context也是該類中的mBase獲取的😄:

@Override
public Context getApplicationContext() {
    return mBase.getApplicationContext();
}
/*
 * 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);
}

最后又追溯到了Context.java中的getSystemService(),什么情況呢,具體實現在哪??一番折騰后,找到了對應的Context實現類:ContextImpl.java

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

@Override
public String getSystemServiceName(Class<?> serviceClass) {
    return SystemServiceRegistry.getSystemServiceName(serviceClass);
}

終於SystemServiceRegistry這個類中有了getSystemService的具體實現,調用的方法其實是getService(),這里三個方法很重要:

/**
 * Creates an array which is used to cache per-Context service instances.
 */
public static Object[] createServiceCache() {
    return new Object[sServiceCacheSize];
}

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

/**
 * Gets the name of the system-level service that is represented by the specified class.
 */
public static String getSystemServiceName(Class<?> serviceClass) {
    return SYSTEM_SERVICE_NAMES.get(serviceClass);
}

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

可以看出三個方法對service進行了創建、獲取和注冊。而SystemServiceRegistry這個類負責創建、啟動和管理所有的服務,當需要用到哪個服務的時候,調用到getService方法然后進行名字的索引來找到需要的服務,里面的關鍵元素:

  • serviceFetcher
  • IBinder,沒錯,實際上剛開始初始化的時候就是通過匿名內部類生成對應名字的服務,然后因為這些都是binder

在啟動APP時進行了必備的service注冊,關於注冊的服務就不列舉了太多了,結構大致如此:

static {
    registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
            new CachedServiceFetcher<AccessibilityManager>() {
        @Override
        public AccessibilityManager createService(ContextImpl ctx) {
            return AccessibilityManager.getInstance(ctx);
        }});

    registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
            new CachedServiceFetcher<CaptioningManager>() {
        @Override
        public CaptioningManager createService(ContextImpl ctx) {
            return new CaptioningManager(ctx);
        }});

    registerService(Context.ACCOUNT_SERVICE, AccountManager.class,
            new CachedServiceFetcher<AccountManager>() {
        @Override
        public AccountManager createService(ContextImpl ctx) {
            IBinder b = ServiceManager.getService(Context.ACCOUNT_SERVICE);
            IAccountManager service = IAccountManager.Stub.asInterface(b);
            return new AccountManager(ctx, service);
        }});
  
     // 代碼省略。。。。
}

感興趣的朋友可以自己看看,進行注冊時候是通過HashMap的方式將服務的名字進行了索引存放。

上部分的代碼中,可以看到有serviceFetcher相關的匿名內部類,每個服務對應了不同的實現,因此方法也是抽象的,下面是三個對應的靜態抽象內部類和一個接口:

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

    public abstract T createService(ContextImpl ctx);
}

/**
 * Override this class when the system service does not need a ContextImpl
 * and should be cached and retained process-wide.
 */
static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> {
    private T mCachedInstance;

    @Override
    public final T getService(ContextImpl unused) {
        synchronized (StaticServiceFetcher.this) {
            if (mCachedInstance == null) {
                mCachedInstance = createService();
            }
            return mCachedInstance;
        }
    }

    public abstract T createService();
}

/**
 * Like StaticServiceFetcher, creates only one instance of the service per process, but when
 * creating the service for the first time, passes it the outer context of the creating
 * component.
 *
 * TODO: Is this safe in the case where multiple applications share the same process?
 * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the
 * case where multiple application components each have their own ConnectivityManager object.
 */
static abstract class StaticOuterContextServiceFetcher<T> implements ServiceFetcher<T> {
    private T mCachedInstance;

    @Override
    public final T getService(ContextImpl ctx) {
        synchronized (StaticOuterContextServiceFetcher.this) {
            if (mCachedInstance == null) {
                mCachedInstance = createService(ctx.getOuterContext());
            }
            return mCachedInstance;
        }
    }

    public abstract T createService(Context applicationContext);
}

我倆整個過程花了15分鍾就了解了getSystemService的具體調用和實現的方式,還是源碼來得快,在進階Android開發過程中,閱讀系統和三方類庫的源碼能夠幫我們事半功倍的效果。


免責聲明!

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



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