Android aspect programming AspectJ

Android AOP scheme (I) - AspectJ - Nuggets AOP is a concept without specific language implementation. It can overcome the shortcomings of languages with only single inheritance features (such as Java). There are many ways to implement AOP, and AspectJ is only one of them. AspectJ annotates the pointcut, pointcut object, etc. in the form of annotations, and then weaves the code into the bytecode of Java during code compilation. This annotation is used to mark ahttps://juejin.cn/post/6888548726424469511

Android aspect programming mainly uses AspectJ, which is only one type. In fact, AspectJ marks the pointcut, pointcut object, etc. in the form of annotation, and then weaves the code into java bytecode during code compilation, so as to realize the significance of aspect programming.

AOP is a concept without specific language implementation. It can overcome the shortcomings of languages with only single inheritance features (such as Java). There are many ways to implement AOP, and AspectJ is only one of them.
AspectJ annotates pointcuts, pointcut objects, etc. in the form of annotations, and then weaves the code into the bytecode of java during code compilation.

Steps for Android to use AspectJ

1: AspectJ annotation

@Aspect 

This annotation is used to mark a class and indicate that the current class is a faceted class so that AspectJ can recognize it. For example:

@Aspect
public class FragmentAspectJInjector {

}

@Pointcut

Annotate a method to define the tangent point, and the parameter is the tangent point expression. For example, a pointcut is defined when the onResume life cycle method of the Fragment is executed:

@Pointcut("execution(* android.app.Fragment+.onResume(..))")
public void fragmentOnResumePointcut() {
}

@Around,@Before,@After

Annotate a method, define the specific weaving code, and the parameter is tangent expression. You can use "& &, |,!" here To combine different Pointcut definitions. For example, we print the current Fragment object before the onResume life cycle of the Fragment:

@Around("fragmentOnResumePointcut()")
public void fragmentOnResume(final ProceedingJoinPoint joinPoint) throws Throwable {
    Object target = joinPoint.getTarget();
    Log.e(TAG, "fragmentOnResume: fragment = " + target);
    joinPoint.proceed();
}

There are many AspectJ annotations, such as @ AfterReturning, @ AfterThrowing, etc., which are not listed here. If you are interested, you can check the official documents. The above annotations can basically meet our needs.

Step 1: create a new Android project

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getFragmentManager().beginTransaction().replace(R.id.fragment, new BlankFragment()).commit();
    }
}

Step 2: add AspectJX dependencies

According to the github document of AspectJX, we are in the build. Net directory of the project root directory Add dependency in gradle

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.2.0-alpha07'
        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'
    }
}

Build. In APP module Application plug-in in gradle

apply plugin: 'android-aspectjx'

Step 3: add facet class

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

    @Pointcut("execution(* android.app.Fragment+.onResume(..))")
    public void fragmentOnResumePointcut() {
    }

    @Around("fragmentOnResumePointcut()")
    public void fragmentOnResume(final ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget();
        Log.e(TAG, "fragmentOnResume: fragment = " + target);
        joinPoint.proceed();
    }

Step 4: build and run APP

Through the logcat window, you can see the following output: you can see that our pointcut has been successfully woven.

E/FragmentAspectJInjector: fragmentOnResume: fragment = BlankFragment{8fafb1e #1 id=0x7f0800a4}\

AspectJ disadvantages

  • If the corresponding class does not implement the corresponding pointcut method, it will not be able to weave in. For example, if the BlankFragment does not implement the onResume method, it will not be able to weave in the code.
  • Unable to process Lambda syntax
  • There will be a series of compatibility problems, such as different versions of R8 and gradle
  • The performance is poor, and the compilation time is significantly longer when the APP project is relatively large.

Keywords: Android

Added by willeadie on Fri, 21 Jan 2022 13:14:20 +0200