同事在進行code review的時候問到我context中的getSystemService方法在哪實現的,他看到了一個ClipBoardManager來進行剪切板存儲數據的工具方法中用到了context.getSystemService(),而此處我使用的是Application級別的Context進行調用的,可IDE跳轉時發現當前類中的getSystemService()方法竟然是抽象的,Context類就是一個抽象類,沒有具體的實現,可在進行調用的時候卻一切正常,同事好奇該方法具體實如今哪實現的,因而我倆一塊兒看源碼和查資料後發現有幾個值得注意的地方:java
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.)app
大意: 獲取的系統service可能和他們的context有緊密聯繫,通常來講不要在不一樣的context之間分享服務對象,如Activity、Application、Service、Provideride
明顯一樣的方法調用的具體實現不一樣,從一樣擁有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獲取的😄:fetch
@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.javathis
@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方法而後進行名字的索引來找到須要的服務,裏面的關鍵元素:code
在啓動APP時進行了必備的service註冊,關於註冊的服務就不列舉了太多了,結構大體如此:component
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開發過程當中,閱讀系統和三方類庫的源碼可以幫咱們事半功倍的效果。