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