I. Basic Concepts:
1. Definition:
Add some extra responsibilities to an object dynamically. Decorator mode is more flexible than subclasses in terms of adding functionality.
2. Application Scenarios:
- You need to extend the functionality of a class.
- Dynamically add functionality to an object, and also dynamically undo it.
3. General Class Diagram:
- Component: Abstract class or interface that decorators and decorators need to implement or inherit from base classes.
- ConcreteComponent: Concrete part of the object being decorated
- Decorate: Decorator role, usually an abstract class that defines a private variable to point to Component.
- ConcreteDecotator: Decorator concrete implementation classes, some that add functionality to methods
Ii. Examples:
1, the Component:
Defines an interface that defines a sing method
public interface Component {
void sing();
}
Copy the code
2, ConcreteComponent:
Defines concrete decorators that implement the Component interface
public class ConcreteComponent implements Component {
@Override
public void sing() {
System.out.print("sing...."); }}Copy the code
3, the Decorator:
Defines an abstract decorator that internally holds a reference to the decorator in order to manipulate the decorator
public abstract class Decorator implements Component {
private Component mComponent;
public Decorator(Component component) {
this.mComponent = component;
}
@Override
public void sing() { mComponent.sing(); }}Copy the code
4, ConcreteDecorator:
Defines specific decorators that can be used to extend functionality within a method.
public class ConcreteDecorator extends Decorator { public ConcreteDecorator(Component component) { super(component); } // Pay first, sing later (add charging function) @override public voidsing() {
System.out.print("Pay in advance...."); super.sing(); }}Copy the code
5. Use:
public class DecoratorTest { public static void main(String[] args){ Component component = new ConcreteComponent(); Decorator decorator = new ConcreteDecorator(component); decorator.sing(); }}Copy the code
6. Replace the decorator:
public class ConcreteDecorator2 extends Decorator{
public ConcreteDecorator2(Component component) {
super(component);
}
@Override
public void sing() {
System.out.print("Playing music..."); super.sing(); }}Copy the code
public class DecoratorTest { public static void main(String[] args){ Component component = new ConcreteComponent(); Decorator decorator = new ConcreteDecorator2(component); decorator.sing(); }}Copy the code
The replacement of a decorator provides some other features to facilitate the replacement of decorators.
Decorator mode in Context
1. Context related class diagram:
- Context corresponds to an abstract class that both decorator and decorator need to inherit
- ContextWrapper corresponds to the decorator’s base class
- ContextImpl corresponds to the decorator, the class that the logic actually handles
- Activities, Services, and Applications correspond to the decorator’s concrete implementation classes
2, the Context
public abstract class Context { ...... public abstract void startActivity(Intent var1); public abstract void startActivity(Intent var1, @RecentlyNullable Bundle var2); . }Copy the code
Context, as an abstract base, defines four abstract methods of component startup, resource acquisition, class loading, file management, permission management and so on
3, ContextImpl
class ContextImpl extends Context {
......
@Override
public void startActivities(Intent[] intents, Bundle options) {
warnIfCallingFromSystemProcess();
if ((intents[0].getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivities() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag on first Intent."
+ " Is this really what you want?"); } mMainThread.getInstrumentation().execStartActivities( getOuterContext(), mMainThread.getApplicationThread(), null, (Activity) null, intents, options); }... }Copy the code
ContextImpl, as the decorator, internally defines the concrete implementation of methods such as the Activity launch
4, ContextWrapper:
public class ContextWrapper extends Context { Context mBase; public ContextWrapper(Context base) { mBase = base; } // Get a reference to the decorator ContextImpl protected void attachBaseContext(Context base) {if(mBase ! = null) { throw new IllegalStateException("Base context already set"); } mBase = base; }... @Override public void startActivities(Intent[] intents) { mBase.startActivities(intents); } @Override public void startActivities(Intent[] intents, // Call the ContextImpl method mBase.startActivities(intents, options); }... }Copy the code
ContextWrapper acts as the decorator’s base class, holds a reference to the decorator ContextImpl, and calls the logic in ContextImpl within its own methods
Create Application Context
ActivityThread:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
Application app = r.packageInfo.makeApplication(false, mInstrumentation); . }Copy the code
The Application instance object is created by calling LoadedApk’s makeApplication method.
LoadedApk:
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { ...... ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); appContext.setOuterContext(app); . }Copy the code
The Decorator ContextImpl object is created, and the Application is created by calling the newApplication method of Instrumentation.
Instrumentation:
static public Application newApplication(Class<? > clazz, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException { Application app = (Application)clazz.newInstance(); app.attach(context);return app;
}
Copy the code
The ContextImpl object is passed in by calling the Application (decorator) attach method.
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
Copy the code
The ContextImpl object is passed in by calling the attachBaseContext method of the decorator base class ContextWrapper, and then operates on the decorator.
Create an Activity Context:
ActivityThread:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ...... / / (1) to create a ContextImpl ContextImpl appContext = createBaseContextForActivity (r); Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); / / (2) create the Activity object Activity. = mInstrumentation newActivity (cl, component getClassName (), r.i ntent); .if(activity ! = null) { appContext.setOuterContext(activity); Attach (appContext, this, getInstrumentation(), r.toy, R.I.dent, app, R.I.ntent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback); .returnactivity; }}}Copy the code
The attach method of the Activity is called:
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) { attachBaseContext(context); . }Copy the code
The ContextImpl is created and passed into the Activity
7. Create Service Context
Service startup finally calls the ActivityThread handleCreateService method ActivityThread:
private void handleCreateService(CreateServiceData data) { ...... Service service = null; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); Service = (service) cl.loadClass(data.info.name).newinstance (); . / / (2) create ContextImpl ContextImpl context. = ContextImpl createAppContext (this, packageInfo); context.setOuterContext(service); Application app = packageInfo.makeApplication(false, mInstrumentation); / / (3) ContextImpl incoming service. Attach (context, this, the data. The info. Name, data. The token, app, ActivityManager. GetService ()); service.onCreate(); . }}Copy the code
Service:
public final void attach( Context context, ActivityThread thread, String className, IBinder token, Application application, Object activityManager) { attachBaseContext(context); . }Copy the code
Service creation is complete and ContextImpl is passed in