Using apt in Android Studio

Using apt in Android Studio

1. Introduction

Are you still blindly copying and pasting boring and repetitive codes? How is this different from moving bricks? Have you ever thought: you use code to write an automated APP, but why the code itself lacks vitality? Master Android-apt, eliminate repetitive codes, and let you write code as elegantly as writing poetry.

2. What is apt?

Apt means: annotation processing tool. This tool is amazing. It can automatically generate specific Java files during compilation through annotations to realize automatic code writing.

Q: What’s the point? Why should I automate the code that I can write by myself?

Brother, are you going to use your copy-and-paste skills again? Be patient, read this article carefully, and you will fall in love with this guy.

I believe you must have heard of the two well-known open source libraries ButterKnife and Dagger2, and you should know why I mentioned them. That's right! Both of these open source libraries are based on apt.

3. After saying so much, how to use it? Don't worry, let's build the environment first (based on gradle plugin version 2.2.0 or above)

1. Create a new Java module in Android Studio to store the annotation processing logic. The name is arbitrary, I usually name it apt. The most important thing: add the annotation processing dependency to the app module: annotationProcessor project(':apt')

(Explanation: Since the Android module does not contain apt-related classes, a new Java module is needed to write apt logic. What? You don't believe it? If you don't believe it, write a class that inherits AbstractProcessor and try it)

2. Create a new module (either android or java) to store annotations. The name is arbitrary. I named it anno. Add the dependency compile project (':anno') to the build.gradle file of app and apt.

(Why create a new module to hold the annotation class instead of putting it in the app module or apt module: the main reason is that the app module and the apt module cannot directly depend on each other. As for why they cannot depend directly, I will not go into details. In short, if you don’t believe it, you will know it if you try it!)

3. In build.gradle of apt, add the following dependencies. At this point, our environment configuration work has come to an end.

(Among them: 1. auto-service is used to automatically generate configuration files in a specific path after annotation; 2. javapoet is a tool used to conveniently generate java files with apt. I believe that this explanation is still confusing to everyone, don't worry, keep reading)

4. The environment is set up, and now it’s time to show your operation

1. First, create a new annotation class in the anno module

  1. @Retention(RetentionPolicy.SOURCE)
  2. @Target(ElementType.METHOD)
  3. public @interface Test {
  4. String value();
  5. }

2. Create a new annotation processing class in the apt module, inheriting from AbstractProcessor

  1. public class TestProcessor extends AbstractProcessor{
  2. @Override
  3. public boolean process( Set <? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  4. return   false ;
  5. }
  6. }

3. Since apt is to automatically generate java files, we need to construct a target class. Suppose we want to generate such a class

  1. public class TestClass {
  2.  
  3. public   static void main(String[] args){
  4. System. out .println( "Hallo world!" );
  5. }
  6.  
  7. }

4. Operate the annotation processing class to generate the target java file

  1. @AutoService(Processor.class)
  2. @SupportedAnnotationTypes({
  3. "com.aop.anno.Test"  
  4. })
  5. public class TestProcessor extends AbstractProcessor{
  6.  
  7. @Override
  8. public boolean process( Set <? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  9.  
  10. //Generate TestClass class
  11. TypeSpec.Builder tb = TypeSpec.classBuilder( "TestClass" )
  12. .addModifiers( Modifier.PUBLIC );
  13.  
  14. //Generate main method
  15. MethodSpec.Builder mb = MethodSpec.methodBuilder( "main" )
  16. .addModifiers(Modifier. PUBLIC , Modifier. STATIC )
  17. . returns (void.class)
  18. .addParameter(String[].class, "args" );
  19.  
  20. //Generate code block and add it to the main method
  21. for (TypeElement e : ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(Test.class))){
  22. CodeBlock cb = CodeBlock.builder()
  23. .addStatement( "$T.out.println(\"$L + $L\")" , System.class,
  24. e.getAnnotation(Test.class).value(), e.getSimpleName())
  25. .build();
  26. mb.addCode(cb);
  27. }
  28.  
  29. tb.addMethod(mb.build());
  30.  
  31. JavaFile jf = JavaFile.builder( "com.example.apt" , tb.build()).build();
  32. //Write the code into the java file
  33. try {
  34. jf.writeTo(processingEnv.getFiler());
  35. } catch (IOException e) {
  36. e.printStackTrace();
  37. }
  38.  
  39. return   true ;
  40. }
  41. }

Roughly speaking the steps are:

(1) Add the @AutoService(Processor.class) annotation, which will automatically generate a configuration file in the specified path:

apt/build/classes/main/META-INF/services/javax.annotation.processing.Processor;

(2) Add the @SupportedAnnotationTypes annotation to configure the annotation types that this class will handle. (Pass in a String type parameter in the format of package name + class name);

(3) Use javapoet to write code and build logic. For specific usage, please see here;

(4) The main logic of generating code blocks is: traverse all classes annotated with @Test, extract the annotation content and class name and print them out.

5. Add @Test annotation to the class. Let’s try it with MainActivity.

  1. @Test( "abc" )
  2. public class MainActivity extends AppCompatActivity {
  3.  
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. }
  9. }

6. Rebuild the project and find the target java file in the path app/build/generated/source/apt/debug.

The TestClass code is as follows:

  1. public class TestClass {
  2. public   static void main(String[] args) {
  3. System. out .println( "abc + MainActivity" );
  4. }
  5. }

5. But it’s useless?

Indeed, up to this point, we have used dozens of lines of code to generate a TestClass of 5 lines of code. This operation can be described in four words: boring.

However, the following operation will give you a refreshing feeling. First, we create a few test classes. Suppose we create four test classes: ActivityA, ActivityB, ActivityC, ActivityD, and add the @Test annotation to them. Then rebuild, you will find that our TestClass has changed:

  1. public class TestClass {
  2. public   static void main(String[] args) {
  3. System. out .println( "A + ActivityA" );
  4. System. out .println( "B + ActivityB" );
  5. System. out .println( "C + ActivityC" );
  6. System. out .println( "D + ActivityD" );
  7. System. out .println( "abc + MainActivity" );
  8. }
  9. }

Suddenly I understand! So, this is how it works! At this point, have you felt the charm of apt? Yes, it can help you get rid of duplicate codes and stop copying and pasting.

<<:  The sixth episode of Aiti Tribe Clinic: How does machine learning judge emergencies?

>>:  The sixth session of the Aiti Tribe Technical Clinic

Recommend

How to optimize advertising creatives? 3 analysis methods

The impact of advertising materials on advertisin...

Wild rabbits are a disaster in Australia, and Sichuan people are very "anxious"

Audit expert: Ran Hao Well-known science writer W...

Would you like to know the 10 tips for Weibo operation and promotion?

Would you like to know about the ten tips for Wei...

Magic Electric v1.12 Unlimited BT magnet downloader, download shareware!

Software Information Name: Magic Electricity Pack...

Is spiciness a kind of pain? Why does it make people feel "painful and happy"?

In the world of food, there is a unique stimulati...

An inventory of common online platform promotions!

Before starting online promotion , you need to un...

Is your phone secure?

Many people may have been scared by the "sup...

How to create a hit on Zhihu!

When it comes to creating high likes on Zhihu, th...

How to develop an Apple App of the Year? See what the founder of Replay said

Replay is a video editing software with similar f...