在组件中获取服务对象的大致步骤

原创 2013年12月03日 11:18:27

我们可以在Activity、Service中获取到服务的管理对象,从而可以让服务工作,完成客户端的请求。

在aidl文件编译生成的java文件中,有关服务管理对象(XXManager)、服务接口(IXXManager)、根(IXXManager.Stub)、服务(XXManagerService)、服务代理(IXXManager.Stub.Proxy)之间的大致类关系如图:

具体可以看下aidl文件编译后生成的Java文件。

现在,在Activity中通过获取PowerManager服务为例:

1、在Activity中通过:PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);获取电源服务管理对象。

对于PowerManager类中的构造:

    public PowerManager(Context context, IPowerManager service, Handler handler) {
        mContext = context;
        mService = service;
        mHandler = handler;
    }

其上的IPowerManager service参数给了 PowerManager中的成员变量mService,进而可以调用代理类中相应的方法,比如:

PowerManager中的方法,

    public boolean isScreenOn() {
        try {
            return mService.isScreenOn();
        } catch (RemoteException e) {
            return false;
        }
    }

2、进入Context类中,查看方法getSystemService的工作机制,此类中方法为:

public abstract Object getSystemService(String name);

3、上面方法是抽象的,看其实现类ContextImpl:

@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);

return fetcher == null ? null : fetcher.getService(this);
}

说明:

//以String为key,ServiceFetcher为value

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

添加元素到的操作在方法:

private static void registerService(String serviceName,
ServiceFetcher fetcher) {
if (!(fetcher instanceof StaticServiceFetcher)) {
fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
}
SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}

而实际上,调用这个发给方法的实在ContextImpl中的一个静态代码块中:

static {

................

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());
}
});

................

}

通过静态代码块调用的方法,将相应的服务管理对象添加到了SYSTEM_SERVICE_MAP中。

4、对于静态代码块中的一个内部方法等下再看,回到getSystemService方法中的return fetcher == null ? null : fetcher.getService(this);

看下ServiceFetcher,源码如下:

/**
* Override this class when the system service constructor needs a
* ContextImpl. Else, use StaticServiceFetcher below.
*/
/* package */static class ServiceFetcher {
int mContextCacheIndex = -1;


/**
* Main entrypoint; only override if you don't need caching.
*/
public Object getService(ContextImpl ctx) {
ArrayList<Object> 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");
}
}


/**
* Override this class for services to be cached process-wide.
*/
abstract static class StaticServiceFetcher extends ServiceFetcher {
private Object mCachedInstance;


@Override
public final Object getService(ContextImpl unused) {
synchronized (StaticServiceFetcher.this) {
Object service = mCachedInstance;
if (service != null) {
return service;
}
return mCachedInstance = createStaticService();
}
}


public abstract Object createStaticService();
}

上面的代码中可以通过getService调用createService方法,分别从集合HashMap中取得的ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);会调用静态代码中相应的方法,虽然在return fetcher == null ? null : fetcher.getService(this);只是调用了getService方法,但是前面代码也可一知道。

5、回到静态代码中的内部方法:

// Note: this was previously cached in a static variable, but
// constructed using mMainThread.getHandler(), so converting
// it to be a regular Context-cached 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());
}
});

获取一个电源管理,并且最终返回给我们初始调用的方法getSystemService。

6、内部方法方法体:

IBinder b = ServiceManager.getService(POWER_SERVICE);
IPowerManager service = IPowerManager.Stub.asInterface(b);
return new PowerManager(ctx.getOuterContext(), service,
ctx.mMainThread.getHandler());

第一行:IBinder b = ServiceManager.getService(POWER_SERVICE);从ServiceManager服务注册管理类中取出PowerManagerService对象,可以看下是怎么添加上去的,见下面代码。

其实在SystemServer中:

power = new PowerManagerService();
ServiceManager.addService(Context.POWER_SERVICE, power);

第二行:IPowerManager service = IPowerManager.Stub.asInterface(b);获取代理对象。

调用的是IPowerManager.Stub.asInterface(b)方法,看下AIDL文件编译生成的java文件,就会知道。

这是个例子代码:

public static com.example.testactivitystart.HH asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.testactivitystart.HH))) {
return ((com.example.testactivitystart.HH)iin);
}
return new com.example.testactivitystart.HH.Stub.Proxy(obj);
}

最终通过return new com.example.testactivitystart.HH.Stub.Proxy(obj);获取该服务相对应的服务代理对象。

第三行:return new PowerManager(ctx.getOuterContext(), service,ctx.mMainThread.getHandler());

回到PowerManager类中的构造方法,

    /**
     * {@hide}
     */
    public PowerManager(Context context, IPowerManager service, Handler handler) {
        mContext = context;
        mService = service;
        mHandler = handler;
    }

 mService = service;电源服务代理对象给了电源管理中的成员变量mService。

=============================================================================================

Activity:

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);

pm.isScreenOn();

===================================================================================================

客户段通过电源管理pm.isScreenOn()方法,

    public boolean isScreenOn() {
        try {
            return mService.isScreenOn();
        } catch (RemoteException e) {
            return false;
        }
    }

继而,调用电源服务代理中的isScreenOn()方法。

最后,调用电源服务中的方法isScreenOn()。他们之间的联系通过Binder机制实现。







相关文章推荐

Activity 如何获取到各种服务service

1、每个activity都是ContextImpl(从源码创建一个activity的代码中可以看出) 2、每个activity可以getSystemService(String name)其实调用的...

工厂方法模式与抽象工厂模式

工厂方法模式与抽象工厂模式

Android 获取ROOT权限原理解析

一、 概述 本文介绍了android中获取root权限的方法以及原理,让大家对android玩家中常说的“越狱”有一个更深层次的认识。   二、 Root的介绍 1.       Root 的...

面向对象编程(OOP)、面向组件编程(COP)、面向方面编程(AOP)和面向服务编程(SOP)【转】

面向对象编程(OOP)、面向组件编程(COP)、面向方面编程(AOP)和面向服务编程(SOP)【转】2008-12-13 22:471、什么是面向对象编程(Object-Oriented Progra...
  • junecau
  • junecau
  • 2011年04月28日 20:09
  • 410

自己封装的Socket组件,实现服务端多进程共享Socket对象,协同处理客户端请求

DotNet.Net.MySocket是SLB.NET(Server Load Balance服务器负载均衡)项目中的核心组件。 在实际的项目中发现,单进程的服务端处理高并发的客户请求能力有限。 ...

关于面向对象,面向组件和面象服务的简单讨论

java语言设计者觉得c,c++都是面向机器的,开发者必须了解机器,解决商业问题也必须让商业系统去适应机器,这对开发者来说,是很痛苦的 所以java开发者提倡面向对象,将万事万物都看作是对象,让...
  • ynwso
  • ynwso
  • 2015年03月20日 10:31
  • 805

百度 地图 slidingmenu 黑边 使用截图的方式解决黑边问题,步骤: 1.slidingMenu打开的时候调用BaiduMap的snapshot方法截图获取Bitmap对象; 2.使用

FrameLayout         android:id="@+id/frameLayout_map_id"         android:layout_width="match_paren...

直接获取某个组件的对象(this[]用法)

有这样一个需求:假如你new了一百次Button,同时这些button的id分别赋值如btn1.id = "button1"; btn2.id = "button2";以此类推。当100个bu...
  • sws9999
  • sws9999
  • 2011年04月09日 00:45
  • 409

【学习笔记】day1_快速入门 14_电话拨号器定义布局&获取组件对象

Java代码: package com.itheima.dialer; import android.net.Uri; import android.os.Bundle; import andro...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在组件中获取服务对象的大致步骤
举报原因:
原因补充:

(最多只允许输入30个字)