您的位置:首页 > 移动开发 > Objective-C

拓展篇:如何获得AlarmManager对象

2012-05-09 15:20 246 查看
从AlarmManager的源码中可以看出,它只有一个访问权限为default的构造方法

AlarmManager(IAlarmManager service) {
mService = service;
}


那么,就只有它同包的类才能通过new的方法获得AlarmManager的实例,我们在自己的应用中是不能通过new这样的方法来得到它的实例的,也没有类似的getInstance()方法。

要想获得AlarmManager的实例,就必须通过Conetxt.getSystemService(Context.ALARM_SERVICE)的手段来获取。

而且,在一个Activity和一个Service中都可以试用Conetxt.getSystemService(Context.ALARM_SERVICE),因为Service和Activity都有相同的父类ContextWrapper。所有,必须先分析一下Context的继承体系,找出getSystemService()方法实际的位置和作用。

1、Context的简单分析

下面是Context的介绍

/**
* Interface to global information about an application environment.  This is
* an abstract class whose implementation is provided by
* the Android system.  It
* allows access to application-specific resources and classes, as well as
* up-calls for application-level operations such as launching activities,
* broadcasting and receiving intents, etc.
*/


翻译:Context提供了关于应用环境全局信息的接口。它是一个抽象类,它的执行被Android系统所提供。它允许获取以应用为特征的资源和类型。同时启动应用级的操作,如启动Activity,broadcasting和接收intents。

查看Conetxt的源码:

可以发现大部分都是静态的常量字符串和抽象方法,只有少部分有实现,而getSystemService()也是一个抽象的方法。

/**
* 根据传递进来的名字,返回一个系统级应用的句柄。
* 注意:通过这种API获得的系统服务与这个context紧密结合在一起。一般情况下,不会在不同的context之间传递和共享这个系统级服务。(
* 如Activities,Applications, Services, Providers等等)
*/
public abstract Object getSystemService(String name);
Context中的getSystemService没有具体的实现,所以还要继续的看Conetxt的子类ContextWrapper。

2、ContextWrapper的简单分析

下面是ContextWrapper的成员变量和构造器:

public class ContextWrapper extends Context {
Context mBase;

public ContextWrapper(Context base) {
mBase = base;
}
..........
}


Google  API的介绍:

/**
* Proxying implementation of Context that simply delegates all of its calls to
* another Context.  Can be subclassed to modify behavior without changing
* the original Context.
*/
翻译下:Context的代理实现,仅仅代表对另一个Context的所有请求

可以修改子类的行为,而不用修改原来的Context。

这是API的介绍,我翻译的不准确,不过大概可以理解:

先从字面意思来理解,ContextWrapper意思就是Context的包装类,也就是对Context的进一步的包装。就如果Integer对int的包装,

我们同样可以通过Integer实现对一个整形的各种操作。

可以看到ContextWrapper中只有一个访问权限为default的Context对象的引用mBase,

注意:这里的mBase只是一个引用,具体引用的对象还要根据传递进来的对象来确定,只要是Context对象的子类就行。

ContextWrapper重写了Context方法里面的所有方法,除了一个自己的构造器和get器,没有重新定义自己的方法。

而它重写的所有方法,几乎都一模一样,随便举几个例子:
//这是获得AssetManager的方法
@Override
public AssetManager getAssets() {
return mBase.getAssets();
}
//这是获得PackageManager的方法
@Override
public PackageManager getPackageManager() {
return mBase.getPackageManager();
}
// 这是获得系统级服务的方法
@Override
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
可以看到,所有的方法都是同一种模式:都是调用mBase对象中的方法,而mBase又是一个Context对象,所以,它是通过一个ContextWrapper对象

改变一个Context对象(mBase)。也就是API中所说的:Context的代理实现,仅仅代表对另一个Context的所有请求

可以修改子类的行为,而不用修改原来的Context。

可以看到在ContextWrapper中也没有具体的实现,所以还要往下面继续的追踪。在看ContextWrapper的子类

3、ContextThemeWrapper的简单分析

ContextThemeWrapper里面的代码比较少。

看API的介绍:

/**
* A ContextWrapper that allows you to modify the theme from what is in the
* wrapped context.
*/
翻译:允许你修改一个你包装的context对象的风格。

也就是说,这个类主要是用来修改一个Context对象的风格。这也是为什么Service对象不是继承ContextThemeWrapper,而是继承它的父类ContextWrapper,因为Service不需要界面,当然无所谓风格。

不过,它依然重写了父类的getSystemService()方法:

@Override
public Object getSystemService(String name) {
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
if (mInflater == null) {
mInflater = LayoutInflater.from(mBase).cloneInContext(this);
}
return mInflater;
}
return mBase.getSystemService(name);
}

可以看到,它的具体实现只针对一个LayoutInflater对象,对于其他的服务,依然调用的是mBase.getSystemService()方法。

所以,还要继续往下面看。看它的子类Activity

4、Activity的简单分析

Activity的作用就不说了,学Android应该都知道。

查看Activity的源码,很长哈,找到里面的getSystemService()方法,如下:

@Override
public Object getSystemService(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;
}
return super.getSystemService(name);
}
可以发现,Activity重写了父类的Activity,其中只有WindowManager和SearchManager的实现,其余的就是super.getSystemService()。

而他父类的getSystemService()方法,也只有LayoutInflater的实现,所以,仔仔细细的分析一遍,我们都没有发现getSystemService()方法中有我们所想要的AlarmManager()的

实现。

那么,从另一个角度,系统需要启动一个应用程序,那么,就必须要启动一个Activity,那么就必须需要实例化Activity对象。Activity对象的启动和实例化,都是由Android系统完成的。那么,Activity究竟是如何实例化的。Activity中并没有显示的构造方法,那么就只能来自父类ContextThemeWrapper了,ContextThemeWrapper有两个构造方法

public ContextThemeWrapper() {
super(null);
}

public ContextThemeWrapper(Context base, int themeres) {
super(base);
mBase = base;
mThemeResource = themeres;
}


显然,要想得到一个能够用于实际操作的Activity对象,会调用第二个构造方法,而这个构造方法又使用super(base),又会调用ContextWrapper的构造方法:

public ContextWrapper(Context base) {
mBase = base;
}


所以,可以明白,关键是这个实例化Activity传递的Context对象究竟是谁的Context。

最终发现,实例化Activity的Conetxt对象是ApplicationContext的对象,而ApplicationContext.java属于未开源的代码,

public class ApplicationContext extends Context


里面的getSystemService()方法的具体实现:

public Object getSystemService(String name)
{
if("window".equals(name))
return WindowManagerImpl.getDefault();
if("inflate".equals(name))
return new WidgetInflate(this);
if("alarm".equals(name))
return new AlarmManager();
if("power".equals(name))
return getPowerManager();
if("notification".equals(name))
return getNotificationManager();
if("keyguard".equals(name))
return new KeyguardManager();
if("location".equals(name))
return getLocationManager();
else
return null;
}


所以,纠结了一圈才发现,得到一个AlarmManager原本很简单,却被Google给隐藏起来了。现在就很好理解了,可以想到,在Service中,传递的也是ApplicationContext的Context对象,所以,在Activity和Service中都可以通过

getSystemService(name)来获得一个系统级的服务。

最后来个总结:

String serviceName=".....";

getSystemService(serviceName)的生命旅程:

1、首先Activity调用自己getSystemService():

@Override
public Object getSystemService(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;
}
return super.getSystemService(name);
}


2、如果不满足判断的条件,那么就会去调用父类的getSystemService():

@Override
public Object getSystemService(String name) {
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
if (mInflater == null) {
mInflater = LayoutInflater.from(mBase).cloneInContext(this);
}
return mInflater;
}
return mBase.getSystemService(name);
}


3、在如果不满足判断的条件,就返回mBase.getSystemService(name),而mBase是一个ApplicationConetxt对象,那么就会去调用ApplicationConetxt的getSystemService()

方法:

public Object getSystemService(String name)
{
if("window".equals(name))
return WindowManagerImpl.getDefault();
if("inflate".equals(name))
return new WidgetInflate(this);
if("alarm".equals(name))
return new AlarmManager();
if("power".equals(name))
return getPowerManager();
if("notification".equals(name))
return getNotificationManager();
if("keyguard".equals(name))
return new KeyguardManager();
if("location".equals(name))
return getLocationManager();
else
return null;
}


就这样一步步的执行,知道找到为止。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息