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.