Management of various services using the android Context
Often, when we need to use a service, we can get the following information through Context. getSystemService (name); for example, when we want to know the current phone status (call/power-off/SIM card status), we can get TelephonyManager through Context:
Final TelephonyManager tm = (TelephonyManager) getSystemService (Context. TELEPHONY_SERVICE );
Do you know why various services can be obtained through Context? Let's take a look.
We know that the Implementation class of Context is ContextImpl, so let's take a look at ContextImpl. through code analysis, you will soon know that in ContextImpl, you can create and save various service objects in the factory mode and single-column mode. this is complex, so we will introduce it one by one:
(1) define in ContextImpl, for example, the next HashMap,
Private static final HashMap SYSTEM_SERVICE_MAP = new HashMap ();
This is a static/final HashMap, which stores the ServiceFetcher of each service. Here, String identifies the current service name, And ServiceFetcher is the tool class of this service! It is actually the object used to create the service.
When we get this service through getSystemService (String name), we use this ServiceFetcher to get the services we need:
public Object getSystemService(String name) { ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); }The code above shows that it is actually obtained through ServiceFetcher's getService.
(2) Let's focus on what functions ServiceFetcher implements.ServiceFetcher is actually a simple design concept of the factory model, and it is also used in a single-column mode! When getService () is used to obtain a service object, first determine whether the service object already exists. If yes, return immediately. Otherwise, call createService () and save the created service object. the ServiceFetcher of different services implements createService () for different object creation methods (). in this way, the ServiceFetcher of each service in SYSTEM_SERVICE_MAP can be used to obtain its object.
/*package*/ static class ServiceFetcher { int mContextCacheIndex = -1; /** * Main entrypoint; only override if you don't need caching. */ public Object getService(ContextImpl ctx) { ArrayList cache = ctx.mServiceCache; Object service; synchronized (cache) { if (cache.size() == 0) { // Initialize the cache vector on first access. // At this point sNextPerContextServiceCacheIndex // is the number of potential services that are // cached per-Context. for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) { cache.add(null); } } else { service = cache.get(mContextCacheIndex); if (service != null) { return service; } } service = createService(ctx); cache.set(mContextCacheIndex, service); return service; } } /** * Override this to create a new per-Context instance of the * service. getService() will handle locking and caching. */ public Object createService(ContextImpl ctx) { throw new RuntimeException("Not implemented"); } }
(
3) initialize SYSTEM_SERVICE_MAP.
There is a static code block in contexqp to initialize ServiceFetcher of all services and add it to SYSTEM_SERVICE_MAP.
Let's take a look at the initialization of the Power Management Service:
registerService(POWER_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(POWER_SERVICE); IPowerManager service = IPowerManager.Stub.asInterface(b); return new PowerManager(ctx.getOuterContext(), service, ctx.mMainThread.getHandler()); }});RegisterService is actually a static method. Its main job is SYSTEM_SERVICE_MAP.put (serviceName, fetcher );
Through the above analysis, we can have a good understanding of the mixed use of the factory mode and single-column mode. Is there a problem with this understanding? It seems that the above design pattern is more appropriate to enjoy the Yuan pattern! Of course, I don't think the above design model is actually a name! It is important to know how to solve the actual problem! In fact, I think that the "share" mode is equivalent to the "Factory" mode + single-column mode + (or another mode ). it should be clear that the focus of the metadata sharing mode is: sharing, not repeating. the objective is to solve the problem: a large number of repeated objects are used.