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.