android装饰者模式,Context中的装饰器模式

对于Android开发者来说,Context再熟悉不过,通过Context,我们可以启动一个Activity,启动一个Service服务,发送一个广播,注册、注销广播接收器,Context就像一个大总管,管理者4大组件。本篇就来聊聊Context中使用到的设计模式-装饰器模式。

Context类族

Context是一个抽象类,他的子类有Application、Activity、Service,以及ContextWrapper、ContextThemeWrapper。

Application继承于ContextWrapper。

Activity继承于ContextThemeWrapper,ContextThemeWrapper又继承于ContextWrapper。

Service继承于ContextWrapper。

5d9f8a9f5d4cdb63d780e30345f54084.png

ContextThemeWrapper为ContextWrapper提供了主题相关的能力,而Activity继承于ContextThemeWrapper,所以Activity就有了主题的能力。

ContextWrapper是什么

ContextWrapper继承于Context这个抽象类,它的构造方法传入了一个Context参数的变量base,如果传入null,则需要attachBaseContext()方法中传入。

内部复写了大量的Context抽象方法,例如startActivity()、sendBroadcast()、startService(),转调传入的base成员变量。

所以其实真正干活的是传入的Context对象base,ContextWrapper相当于一个装饰器。base对象则为被装饰器对象。

public class ContextWrapper extends Context {

//被装饰的Context对象

Context mBase;

public ContextWrapper(Context base) {

mBase = base;

}

protected void attachBaseContext(Context base) {

if (mBase != null) {

throw new IllegalStateException("Base context already set");

}

mBase = base;

}

//省略其他代码...

@Override

public SharedPreferences getSharedPreferences(String name, int mode) {

return mBase.getSharedPreferences(name, mode);

}

@Override

public void startActivity(Intent intent, Bundle options) {

mBase.startActivity(intent, options);

}

@Override

public void sendBroadcast(Intent intent) {

mBase.sendBroadcast(intent);

}

@Override

public Intent registerReceiver(

BroadcastReceiver receiver, IntentFilter filter) {

return mBase.registerReceiver(receiver, filter);

}

@Override

public ComponentName startService(Intent service) {

return mBase.startService(service);

}

@Override

public boolean stopService(Intent name) {

return mBase.stopService(name);

}

//省略其他代码...

}

复制代码

真正干活的ContextImpl

上面说到真正干活的Context通过构造或者attachBaseContext()方法传入。我们用Android Studio查找一个引用,发现Activity、Service、Application都调用了ContextWrapper构造方法,我们以Application为例来看下。

我们看到Application的构造方法调用了super(null),Application也继承于ContextWrapper,所以这个super(null)调用的是ContextWrapper的带Context构造参数构造方法。

public class Application extends ContextWrapper implements ComponentCallbacks2 {

public Application() {

super(null);

}

}

复制代码

Application构造传入了null,所以传入被装饰的Context实例只能在attachBaseContext(context)的调用处了,搜索一下,Application的attach(context)方法调用了attachBaseContext(context)。

final void attach(Context context) {

attachBaseContext(context);

mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;

}

复制代码

继续追踪,看下是谁调用了Application的attach(context)。Instrumentation类的newApplication()方法,通过反射Application的clazz,创建Application的实例,再调用了attach()方法传入了Context。Context实例是通过调用newApplication()传入的,来看看是谁调用了newApplication()方法。

public class Instrumentation {

public Application newApplication(ClassLoader cl, String className, Context context)

throws InstantiationException, IllegalAccessException,

ClassNotFoundException {

Application app = getFactory(context.getPackageName())

.instantiateApplication(cl, className);

app.attach(context);

return app;

}

}

复制代码

newApplication()方法,在LoadedApk类makeApplication()方法中调用,可以看到Context实例为ContextImpl,它继承了抽象类Context,所以被装饰的类实例为ContextImpl的实例。

public final class LoadedApk {

public Application makeApplication(boolean forceDefaultAppClass,

Instrumentation instrumentation) {

//如果已经创建了,直接返回

if (mApplication != null) {

return mApplication;

}

Application app = null;

String appClass = mApplicationInfo.className;

if (forceDefaultAppClass || (appClass == null)) {

appClass = "android.app.Application";

}

//...省略部分代码

try {

java.lang.ClassLoader cl = getClassLoader();

if (!mPackageName.equals("android")) {

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,

"initializeJavaContextClassLoader");

initializeJavaContextClassLoader();

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

}

//创建被装饰者Context,实例为ContextImpl

ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

//Instrumentation的newApplication()方法在这里被调用

app = mActivityThread.mInstrumentation.newApplication(

cl, appClass, appContext);

appContext.setOuterContext(app);

} catch (Exception e) {

//...省略部分代码

}

mActivityThread.mAllApplications.add(app);

mApplication = app;

return app;

}

}

//ContextImpl继承抽象类Context

class ContextImpl extends Context {

//创建Context实例,实例为ContextImpl

static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {

if (packageInfo == null) throw new IllegalArgumentException("packageInfo");

ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,

null);

context.setResources(packageInfo.getResources());

return context;

}

}

复制代码

以上源码流程来看,被装饰的Context实例为ContextImpl,已经得到了我们的结果了,说个题外话,makeApplication()在什么实际被调用呢?

查看调用链,在ActivityThread中的performLaunchActivity方法中,调用了makeApplication()方法创建Application。

ActivityThread类,我们知道它是App进程中唯一的主线程。performLaunchActivity()方法则为启动Activity时调用生成Activity实例的方法。

public final class ActivityThread extends ClientTransactionHandler {

//生成Activity实例

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

//...省略其他代码

Activity activity = null;

//创建Activity实例

activity = mInstrumentation.newActivity(

cl, component.getClassName(), r.intent);

//这里调用makeApplication()创建Application实例

Application app = r.packageInfo.makeApplication(false, mInstrumentation);

//...省略其他代码

return activity

}

}

复制代码

ContextThemeWrapper-拓展主题的ContextWrapper

ContextThemeWrapper继承于ContextWrapper,带Context参数构造方法和attachBaseContext()则是原封不动的调用回ContextWrapper装饰器中转调ContextImpl的方法。

并提供了2个带Theme对象和themeResId的构造方法。以及提供了setTheme()、getThemeResId()、getTheme()等主题操作、获取的方法。

public class ContextThemeWrapper extends ContextWrapper {

public ContextThemeWrapper() {

super(null);

}

@Override

protected void attachBaseContext(Context newBase) {

super.attachBaseContext(newBase);

}

public ContextThemeWrapper(Context base, @StyleRes int themeResId) {

super(base);

mThemeResource = themeResId;

}

public ContextThemeWrapper(Context base, Resources.Theme theme) {

super(base);

mTheme = theme;

}

//------------- 下面就是拓展的主题相关的方法 -------------

@Override

public void setTheme(int resid) {

if (mThemeResource != resid) {

mThemeResource = resid;

initializeTheme();

}

}

/** @hide */

@Override

public int getThemeResId() {

return mThemeResource;

}

@Override

public Resources.Theme getTheme() {

if (mTheme != null) {

return mTheme;

}

mThemeResource = Resources.selectDefaultTheme(mThemeResource,

getApplicationInfo().targetSdkVersion);

initializeTheme();

return mTheme;

}

//省略其他代码...

}

复制代码

总结

无论Context的继承者有多少,核心Api的实现都在ContextImpl中,诸如Activity、Service等继承ContextWrapper的类,如果增强Context中的Api则复写Context中的抽象方法,如果需要增加特殊中类的方法则新建即可(例如ContextThemeWrapper),这样做的好处是,如果后续需要增加一种更强大的组件,对原有组件可以进行包装拓展,装饰器模式则可以很好的组合新、老组件,只需要新组件继承ContextWrapper,再拓展自己特有的Api即可。

相比继承,装饰器可以多层叠加来组装,可拔插,而无需继承,比继承的具有更多的灵活性。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值