Detailed Explanation of Android Section Programming Knowledge Points

  • 2021-09-20 21:37:35
  • OfStack

Segmented programming may sound strange, but now more and more development teams are using this technology.

First of all, the familiar object-oriented programming OOP usually uses various objects/modules to take charge of specific functions, and tries not to couple each other.

Section programming AOP (aspect-priented programming) is produced to solve the coupling problem in OOP.

For example, there are several modules responsible for networking/data storage/UI in the project, and each module is connected with another Log module.

Although Log does not belong to the first three functions, they are coupled to some extent because they are all connected. When modifying the implementation of Log module, it will affect the implementation of the other three modules.

This article uses the simplest example to describe how AOP solves this problem.

(Actually, this is an AspectJ environment configuration guide)

Installing AspectJ

ApsectJ development on Android consists of several parts, AspectJ gradle plug-in, ApsectJ dependency, and AspectJ compiler.

Installing the AspectJ compiler first is as simple as installing the JAVA Environment 1,

Download link: http://www.eclipse.org/downloads/download.php? file=/tools/aspectj/aspectj-1. 9.0. jar

At present, the latest one has been updated to 1.9. 1. If your computer already has JAVA environment, just run this jar package.

After installation, you need to configure environment variables to the bin directory of aspectj, which will not be described here


export PATH="$PATH:~/Library/Android/sdk/platform-tools"
export PATH="$PATH:/usr/local/opt/gradle/gradle-4.1/bin"
export PATH="$PATH:~/Library/Android/sdk/ndk-bundle"
export PATH="$PATH:~/Library/flutter/bin"
export PATH="$PATH:~/Library/kotlinc/bin"
export PATH="$PATH:~/Library/AspectJ/bin" <- AspectJ Adj. PATH

Running ajc-v after configuration should see the corresponding output

AspectJ Compiler 1.9.0 (1.9.0 - Built: Monday Apr 2, 2018 at 18:52:10 GMT)

Configure Android Gradle to increase AspectJ dependency

The process of building Android App with AspectJ support is to compile the. class file according to the normal process, and then insert the code we need into the. class file with ajc compiler.

You first need to add the AspectJ dependency to the gradle root directory,


buildscript {
  repositories {
    google()
    jcenter()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:3.1.2'
    classpath 'org.aspectj:aspectjtools:1.8.9' //Aspect
    classpath 'org.aspectj:aspectjweaver:1.8.9' //Aspect
  }
}

Then you need to add the following to build. gradle in the project app directory,


apply plugin: 'com.android.application'
//+ Add content 
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath 'org.aspectj:aspectjtools:1.8.9'
    classpath 'org.aspectj:aspectjweaver:1.8.9'
  }
}
repositories {
  mavenCentral()
}

final def log = project.logger
final def variants = project.android.applicationVariants
variants.all { variant ->
  if (!variant.buildType.isDebuggable()) {
    log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
    return;
  }

  JavaCompile javaCompile = variant.javaCompile
  javaCompile.doLast {
    String[] args = ["-showWeaveInfo",
             "-1.8",
             "-inpath", javaCompile.destinationDir.toString(),
             "-aspectpath", javaCompile.classpath.asPath,
             "-d", javaCompile.destinationDir.toString(),
             "-classpath", javaCompile.classpath.asPath,
             "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
    MessageHandler handler = new MessageHandler(true);
    new Main().run(args, handler);
  }
}
//- Add content 

This gradle script is a compilation process of adding an acj after java is compiled.

MessageHandler is an object in AspectJ Tools that receives parameters and then compiles acj.

Finally, add dependencies dependency and support for AspectJ.


implementation 'org.aspectj:aspectjrt:1.9.0'

Create an AspectJ code

The following part of the code looks stupid, but at present, it doesn't matter the specific syntax meaning.

Run up the environment first, and then combine the theory to slowly feel in modifying the code, so you can quickly get started with AOP.

Take an HelloWorld as an example. Our MainActivity does nothing but a basic lifecycle approach.


public class MainActivity extends AppCompatActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }

  @Override
  protected void onStart() {
    super.onStart();
  }

  @Override
  protected void onPause() {
    super.onPause();
  }

  @Override
  protected void onStop() {
    super.onStop();
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
  }
}

Now we're going to write an AspectJ class, which will look a little different from the same Java class, as if it just uses annotations as a medium to let the ACJ compiler know which methods to inject.

What this class does is tell the ACJ compiler to print 1 line of log before each method in MainActivity and output which method is currently executing,


@Aspect
public class AspectTest {
  private static final String TAG = "AspectTest";

  @Pointcut("execution(* phoenix.com.helloaspectj.MainActivity.**(..))")
  public void executeAspectJ() {
  }

  @Before("executeAspectJ()")
  public void beforeAspectJ(JoinPoint joinPoint) throws Throwable {
    Log.d(TAG, "beforeAspectJ: injected -> " + joinPoint.toShortString());
  }
}

The first time I touched AspectJ, I was a little confused when I saw this code. Explain the meaning of several notes under 1.

@ Aspect: Tells the ACJ compiler that this is an AspectJ class @ PointCut: PointCut is a concept in AspectJ, and the other concept following it is JoinPoint, which describes the section to be injected @ Before: Indicates the location to be injected. Commonly used are Before/After/Around, indicating before execution, after execution, and replacing the original method, respectively

Here, the @ PointCut annotated parameter means to inject all the methods in MainActivity, and the parameter uses regular matching syntax.

Let's take a look at the result of this code execution

07-26 16:04:56.611 22823-22823/? D/AspectTest: beforeAspectJ: injected - > execution(MainActivity.onCreate(..))
07-26 16:04:56.661 22823-22823/? D/AspectTest: beforeAspectJ: injected - > execution(MainActivity.onStart())

See that although we didn't write the log print statement in MainActivity, we did it with AspectJ, and inserted our own log before the execution of MainActivity two life cycles.

Usage scenario

AspectJ is only one of the means of AOP, and asm is similar to modify bytecode. The reason why AOP will be understood by more and more people is that it can be decoupled very well abstractly.

Advanced point can use AOP to achieve traceless embedding, data collection, and even modify the code that can't be moved in SDK.

The whole DEMO code above can be obtained from GitHub, and the download link can be obtained by replying to "section" in the background.


Related articles: