introduce

AspectJ is just one of many ways that AOP can be implemented in a concrete way. AOP is a concept that is not implemented in a specific language. It can overcome the disadvantages of languages that have only single inheritance features (such as Java). AspectJ annotates pointcuts, cut objects, and so on in the form of annotations, and then weaves the code into Java bytecode during compilation. For more detailed information on AspectJ, see its website at www.eclipse.org/aspectj/

AspectJ annotations

@Aspect

This annotation is used to annotate a class, indicating that the current class is faceted so AspectJ can recognize it. Such as:

@Aspect
public class FragmentAspectJInjector {}Copy the code

@Pointcut

Annotate a method that defines a pointcut with a pointcut expression. For example, defining a pointcut is performed in the Fragment’s onResume lifecycle method:

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

@around, @before, @after

Annotate a method that defines the code to be woven in, taking a pointcut expression as an argument. Here you can use the “&& and | |,!” To combine the different Pointcut definitions. If we print the current Fragment object before the Fragment’s onResume life cycle:

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

There are many other AspectJ annotations, such as @Afterreturning and @Afterthrowing, which are not listed here. If you are interested, please refer to the official documentation. These notes are basically enough for our needs.

AspectJ using

Now that we’ve covered some aspectJ-related basics, let’s practice using AspectJ in an Android project. There are many open source projects on Github, such as AspectJX: github.com/HujiangTech… Hugo: github.com/JakeWharton… Gradle – android – aspectj – plugin: github.com/uPhyca/grad… Now we’ll use AspectJX directly to implement our functionality, using the Fragment’s onResume life cycle as an example. Although FragmentManager registerFragmentLifecycleCallbacks method can monitor fragments of life cycle, but the API is only new in Android 8.0 version of the old version of Android cannot use. And for the current support, AndroidX and other dependent libraries, can not achieve unified processing, more troublesome.

Step 1: Create an Android Project

In the new APP project, modify the MainActivity layout file and load a Fragment as follows: activity_main.xml


      
<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>
Copy the code

MainActivity.java

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, newBlankFragment()).commit(); }}Copy the code

Step 2: Add AspectJX dependencies

According to AspectJX’s Github documentation, we add dependencies in the project root directory build.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'}}Copy the code

Apply plug-ins to build.gradle in APP Module

apply plugin: 'android-aspectjx'
Copy the code

Step 3: Add the section class

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

    @Pointcut("execution(* android.app.Fragment+.onResume(..) )"
    public void fragmentOnResumePointcut(a) {}@Around("fragmentOnResumePointcut()")
    public void fragmentOnResume(final ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget();
        Log.e(TAG, "fragmentOnResume: fragment = " + target);
        joinPoint.proceed();
    }
Copy the code

Step 4: Build and run your APP

In the logcat window, you can see the following output:

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

You can see that our cut point has been woven in successfully.

AspectJ shortcomings

  • If the corresponding class does not implement the corresponding pointcut method, it will not be able to weave into the code if the BlankFragment method does not implement the onResume method.
  • Unable to handle Lambda syntax
  • There are a number of compatibility issues, such as R8, gradle versions, etc
  • Poor performance, the compilation time is significantly longer when the APP project is large.