infinum android talks #02 - how to write an annotation processor in android
DESCRIPTION
How to write your own annotation processor in Android Studio. Compile time and runtime annotations will be compared to reflection. To conclude, butterknife library will be presented as an example of using compile time annotation processing.TRANSCRIPT
How to writean annotation processor
in AndroidIvan Kušt
• Generics http://docs.oracle.com/javase/tutorial/java/generics/
• Reflectionhttp://docs.oracle.com/javase/tutorial/reflect/
• Annotationshttp://docs.oracle.com/javase/1.5.0/docs/guide/apt/mirror/overview-summary.html
How to write code faster?
Let’s look at our options
Generics Reflection Annotations
Speed Fast Slow Fast (if using compile time)
Ease of use Easy Medium Advanced
“Freedom" - generic types - modify everything at run-time
- generate code during compile
• use generics for type agnostic structures when possible (e.g. lists) - it’s easy and fast
• when that isn’t enough, use annotation processing - generate code that is boring to write
• generated code isn’t “visible” - use reflection to access it at run time from the code that you write
Approach
Let’s get our hands dirty• actually only the keyboard gets dirty over time
• prerequisites:- Android Studio (tested on version 0.4.0)- enable annotation processing(Open preference and navigate to Compiler → Annotation Processors. Check "Enable annotation processing”)- apt plugin https://bitbucket.org/hvisser/android-apt
• what is an annotation processor made of?- definition of annotations using @interface- a class that extends AbstractProcessor- entry containing processor name in META-INF/services/javax.annotation.processing.Processor
Project structure
• API project - annotation definitions - other non-generated code
• Compiler project- annotation processor implementation- annotation definitions (from API project) on classpath
• Application project - android application project- references to API and Compiler projects
API project
• android library project
• contains annotation definitions, for example:
Compiler project
• standard java library project- this is required in order to see APT classes
• API project sources must be in classpath (build.gradle):
Compiler project• AbstractProcessor implementation
- override process(…) method- return true if processing was successfull- add following annotations to processor class: @SupportedAnnotationTypes(“your.package.AnnotationName”)@SupportedSourceVersion(SourceVersion.RELEASE_7)
• create file: src/main/resources/META-INF/services/javax.annotation.processing.Processor
• add fully qualified class name of your processor class to the file (e.g. co.infinum.annotations.processor.TestProcessor)
Application project
• referencing API and Compiler projects in build.gradle:
Butterknife library
• UI dependency injection library
• View injection on Activities or arbitrary objects- no more writing findViewById(…)
• simplifying view holder pattern
• on click listener injection
View injection
class ExampleActivity extends Activity { @InjectView(R.id.title) TextView title; @InjectView(R.id.subtitle) TextView subtitle; @InjectView(R.id.footer) TextView footer;! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ButterKnife.inject(this); // TODO Use "injected" views... }}
• use @InjectView on fields representing view elements- fields can’t be private or protected
• call ButterKnife.inject(this) in onCreate()
Resources• annotations example:
https://github.com/ikust/hello-annotations
• http://turbomanage.wordpress.com/2012/09/28/annotation-processor-android-eclipse/
• https://bitbucket.org/hvisser/android-apt
• http://www.javacodegeeks.com/2012/11/java-annotations-tutorial-with-custom-annotation.html
• http://blog.retep.org/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor/
• http://jakewharton.github.io/butterknife/