Project introduction
A lightweight AOP(Android) application framework that covers the most practical AOP applications. Project address: github.com/xuexiangjys… , if you like, welcome star support!
The design was originally
In our normal development process, we will certainly encounter permission application, thread switch, data cache, exception capture, buried point and method execution time statistics and other problems. These are very common problems and not very difficult to implement, but they are just too cumbersome and can lead to a lot of repetitive, patterned code.
Design ideas
It was Hugo of JakeWharton who first introduced me to the idea of AOP, and reading its source code got me hooked on the dynamic code weaving of AspectJ. I then took a closer look at AspectJ-related technologies, collecting typical AOP application scenarios on Android and implementing them one by one through AspectJ. The result is XAOP, the library.
To solve the pain points
- Fix quick clicks
- Solve Android6.0 above dynamic permission application problem
- Thread free switching issues
- The log burying point is abnormal
- Cache issues (disk cache and memory cache)
- Exception capture processing
- Business interception (login verification, validity verification, etc.)
The integration guide
Add Gradle dependencies
1. Add build.gradle repositories in the project root directory:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
Copy the code
Add xAOP to build. Gradle dependencies in the root directory of your project.
Buildscript {... dependencies {... the classpath 'com. Making. Xuexiangjys. XAOP: XAOP - plugin: 1.1.0'}}Copy the code
Add dependencies and references to xAOP plug-ins in your project’s build.gradle
apply plugin: 'com.xuexiang. Xaop '; Use 1.1.0 version and above implementation 'com. Making. Xuexiangjys. XAOP: XAOP - runtime: 1.1.0' / / if it is a support project, Com. Dead simple. Please use the version 1.0.5 implementation 'xuexiangjys. XAOP: XAOP - runtime: 1.0.5'}Copy the code
4. Perform initialization in Application
XAOP.init(this); // Initialize the plug-in xaop.debug (true); // Enable xaop.setpriority (log.info); / / set the level of log print, the default is 0 / / transferring dynamic application permissions section of the application was refused incident response to monitor XAOP. SetOnPermissionDeniedListener (new PermissionUtils.OnPermissionDeniedListener() { @Override public void onDenied(List<String> permissionsDenied) { // Processing when permission application is rejected}}); Xaop.setinterceptor (new Interceptor() {@override public Boolean Intercept (int type, int Interceptor); JoinPoint JoinPoint) throws Throwable {xLogger. d(" Intercepting, intercepting type :" + type); Switch (type) {case 1: // Do what you want to intercept break; case 2: return true; //return true, directly intercepts the slice execution default: break; } return false; }}); / / set up automatic capture exception handler XAOP. SetIThrowableHandler (new IThrowableHandler () {@ Override public Object handleThrowable (String flag, Throwable) {xlogger. d(" exception caught, exception flag:" + flag); if (flag.equals(TRY_CATCH_KEY)) { return 100; } return null; }});Copy the code
Compatible with Kotlin syntax configuration
Add aspectJx to build. Gradle dependencies in the root directory of the project.
Buildscript {... dependencies {... the classpath 'com. Hujiang. Aspectjx: gradle - android - the plugin - aspectjx: 2.0.10'}}Copy the code
2. Add dependencies and references to the AspectJx plug-in in your project’s build.gradle
Aspectjx {include 'project applicationId'}Copy the code
For details, see the Kotlin-test project.
Confuse configuration
-keep @com.xuexiang.xaop.annotation.* class * {*; } -keep @org.aspectj.lang.annotation.* class * {*; } -keep class * { @com.xuexiang.xaop.annotation.* <fields>; @org.aspectj.lang.annotation.* <fields>; } -keepclassmembers class * { @com.xuexiang.xaop.annotation.* <methods>; @org.aspectj.lang.annotation.* <methods>; }Copy the code
Based on using
Quick click slice
SingleClick
Property sheet
The property name | type | The default value | note |
---|---|---|---|
value | long | 1000 | Quick click interval (ms) |
1. Use @Singleclick to mark click methods. Note that the click method must have the click control View as the method parameter, otherwise it will not work.
2. You can set the time interval for quick clicking (unit :ms). The default value is 1000ms.
@singleclick (5000) public void handleOnClick(View v) {xlogger. e(" Click response!" ); Toastutil.get ().toast(" Click response!" ); hello("xuexiangjys", "666666"); }Copy the code
Dynamically apply for permission slices
Permission
Property sheet
The property name | type | The default value | note |
---|---|---|---|
value | String[] | / | Set of permissions to apply for |
1. Use @permission to mark the method that requires the Permission to execute. You can apply for one or more permissions.
2. When using the @permission annotation, the system automatically determines whether to apply for Permission.
@SingleClick
@Permission({PermissionConsts.CALENDAR, PermissionConsts.CAMERA, PermissionConsts.LOCATION})
private void handleRequestPermission(View v) {
}
Copy the code
Main thread section
1. Use @mainthread to mark the methods that need to be executed in the MainThread.
2. If the @mainthread annotation is used, the MainThread is automatically switched to the MainThread.
@mainThread private void doInMainThread(View v) {mtvHello.settext (" MainThread "); }Copy the code
IO thread slice
IOThread
Property sheet
The property name | type | The default value | note |
---|---|---|---|
value | ThreadType | ThreadType.Fixed | The type of the child thread |
1. Annotate methods that need to be executed in THE I/O thread with @ioThread. The type of the thread pool can be set to ThreadType. Otherwise, the default type is Fixed.
The types of thread pools are as follows:
- Single: Single thread pool
- Fixed: Multi-thread pool
- Disk: Disk read-write thread pool (essentially single thread pool)
- Network: Network request thread pool (essentially multithreaded pool)
2. The @ioThread annotation is used to automatically switch to the SPECIFIED TYPE of I/O threads.
@ioThread (threadType.single) private String doInIOThread(View v) {return "thread.currentThread ().getName(); }Copy the code
Log print section
DebugLog
Property sheet
The property name | type | The default value | note |
---|---|---|---|
priority | int | 0 | Priority of logs |
1. Use @debuglog to mark the methods and classes to be printed. You can set the printing priority. If you do not set the printing priority, the default priority is 0. Note: If the printed priority is lower than the priority set by xaop.setPriority, it will not be printed.
2. During the execution of classes and methods using the @debuglog annotation, the method name, parameters, execution time, and results will be printed.
3. Call Xaop. setISerializer to set the serializer for the print serialization parameter object.
4. Xaop.setlogger can be called to set up the implementation interface for printing. By default, logCAT log printing above the 4000 limit is provided.
@DebugLog(priority = Log.ERROR)
private String hello(String name, String cardId) {
return "hello, " + name + "! Your CardId is " + cardId + ".";
}
Copy the code
Memory cache slice
MemoryCache
Property sheet
The property name | type | The default value | note |
---|---|---|---|
value | String | “” | Memory cache key |
enableEmpty | boolean | true | Whether the cache is allowed to be null for strings, arrays, collections, etc |
1. Annotate methods that require a MemoryCache using @memorycache. Can set the cache key, do not set the default key to the method name (parameters 1 = 1 value | | parameters 2 = 2 value…). Of course, you can also change the auto-generation rules for keys by calling Xaop.seticacheKeyCreator.
2. Annotation methods must return values, otherwise memory cache slicing will not work.
3. The @memoryCache annotation is used to automatically implement the cache policy. The default memory cache used is LruCache.
4. Xaop.initmemorycache can be called to set the maximum number of memory caches. The default is Runtime.geTruntime ().maxMemory() / 1024) / 8
@MemoryCache
private String hello(String name, String cardId) {
return "hello, " + name + "! Your CardId is " + cardId + ".";
}
Copy the code
Disk cache slice
DiskCache
Property sheet
The property name | type | The default value | note |
---|---|---|---|
value | String | “” | Memory cache key |
cacheTime | long | – 1 | Cache duration [unit: s]. The default value is permanent |
enableEmpty | boolean | true | Whether the cache is allowed to be null for strings, arrays, collections, etc |
1. Use @diskcache to mark the method that requires DiskCache. Can set the cache key, do not set the default key to the method name (parameters 1 = 1 value | | parameters 2 = 2 value…). Of course, you can also change the auto-generation rules for keys by calling Xaop.seticacheKeyCreator.
2. You can set the disk cache validity period (unit :s). If this parameter is not set, it takes effect permanently.
3. Annotated methods must return values, otherwise disk cache slicing will not work.
4. The @diskCache annotation is used to automatically implement the cache policy. The default disk cache used is JakeWharton’s DiskLruCache.
5. Xaop.initdiskcache can be called to set the properties of disk cache, including disk serializer IDiskConverter, root directory of disk cache, maximum space of disk cache, etc.
@DiskCache
private String hello(String name, String cardId) {
return "hello, " + name + "! Your CardId is " + cardId + ".";
}
Copy the code
Automatic capture of abnormal slices
Safe
Property sheet
The property name | type | The default value | note |
---|---|---|---|
value | String | “” | Flag to catch an exception |
1. Annotate the methods that need to be caught with @safe. You can set a Flag to catch exceptions. The default Flag is the name of the current class. The method name.
2. Call XAOP. SetIThrowableHandler set an exception of custom processing, can realize to offset processing of the exception. If not set, only stack information for exceptions is printed.
3. The @safe method is used to automatically capture exceptions and handle exceptions in a unified manner to ensure smooth operation.
@Safe(TRY_CATCH_KEY)
private int getNumber() {
return 100 / 0;
}
Copy the code
Custom intercept slice
Intercept
Property sheet
The property name | type | The default value | note |
---|---|---|---|
value | int[] | / | Intercept type |
1. Annotate methods and classes that need to be intercepted using @Intercept. You can set to apply for one or more interception types.
2. Custom intercepting slicing does not work if you do not call xaop.setInterceptor to set the interceptor for slicing.
3. Using classes and methods annotated by @Intercept, interceptors set by XAOP will be automatically called at execution time for interception processing. If the interceptor processing returns true, execution of the class or method is blocked and not executed.
4. Use @Intercept to flexibly Intercept slices. For example, the user login permission.
@singleclick (5000) @debuglog (priority = log.error) @Intercept(3) public void handleOnClick(View v) {xlogger. e(" click response!" ); Toastutil.get ().toast(" Click response!" ); hello("xuexiangjys", "666666"); } @debuglog (priority = log.error) @intercept ({1,2,3}) private String hello(String name, String cardId) {return "hello, " + name + "! Your CardId is " + cardId + "."; }Copy the code
[Note] : When there are multiple slice annotations, they are generally executed from top to bottom.
Use the advanced
Login authentication
In the application, for some functions, such as personal center, wallet, collection and other functions that require us to verify login, we can achieve it through @Intercept business Intercept section.
- Define the business interception type
Public static final int INTERCEPT_LOGIN = 10;Copy the code
- Define interception processing logic
XAOP.setInterceptor(new Interceptor() { @Override public boolean intercept(int type, JoinPoint joinPoint) throws Throwable { switch(type) { case INTERCEPT_LOGIN: if (! Loginactivity.sislogined) {// No loginactivity.sislogined) {ToastUtils. Toast (" Please log in first!" ); ActivityUtils.startActivity(LoginActivity.class); return true; } break; //return true; default: break; } return false; }});Copy the code
- Increase where interception is required
@Intercept
mark
@intercept (INTERCEPT_LOGIN) public void doSomeThing() {ToastUtils. }Copy the code
Q&A
Access problems
Please be sure to read the integration guide carefully before use, as long as you refer to the documentation for each step to access, there will be no problems!
1. Q: My project is the Kotlin project. How do I use it?
A: To configure the Kotlin project, you only need to add aspectJX plug-in on the basis of the original project. For details, please refer to compatible Kotlin Syntax Configuration.
2. Q: Why do I get an error every time I run a buildInvalid byte tag in constant pool
And it automatically generates oneajcore.xxxxxxxxx.txt
File?
A: there is a good chance that your project is currently running androidx, but you are using the support version of XAOP, causing compilation failures. It is important to note that if your project is support, use version 1.0.5; If your project is running androidx, please use version 1.1.0 or above.
3. Q: Why do I compile everything well, but using either slice doesn’t do anything?
A: There are two possible reasons.
- 1. The version of XAOP you are using does not match your project version. For example, if your project is on androidx but you are using the support version of XAOP, slicing will not work.
- 2. You forgot in the project
build.gradle
Added a reference to the XAOP plug-in in.
Apply plugin: 'com.xuexiang.xaop' // reference the Xaop pluginCopy the code
Problems with use
Q: Why do I use it@SingleClick
Annotation click method doesn’t work?
A: Any method marked by @singleclick must have a click control View as an argument, otherwise it will not work.
Q: Why do I use it@Permission
Annotation method, return value invalid?
A: Since the dynamic Permission request is an asynchronous operation, methods annotated by @Permission have no return value.
Supporting facilities
- Simplified version of Android shell template project
- Android shell template project
Wechat official account
More information, welcome wechat search public number: “My Android open source journey”