Blog Infos
Published

Creating custom annotations in Android can greatly enhance the readability, maintainability, and robustness of your code. Annotations allow you to provide metadata to your code elements (such as methods, classes, variables), which can then be used for various purposes like code generation, validation, and more. Here’s a detailed explanation on creating and using custom annotations in Android:

1. Defining Custom Annotations

To define a custom annotation, you use the @interface keyword. Here’s an example of creating a simple annotation:

// Define a custom annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
}
  • @Retention: Specifies how long the annotation is retained. Common values are:
  • RetentionPolicy.SOURCE: Discarded during the compile phase; not available at runtime.
  • RetentionPolicy.CLASS: Recorded in the class file but not available at runtime.
  • RetentionPolicy.RUNTIME: Available at runtime, allowing reflection.
  • @Target: Indicates the kinds of program elements to which the annotation can be applied. Common values are:
  • ElementType.TYPE: Class, interface (including annotation type), or enum declaration.
  • ElementType.FIELD: Field (including enum constant).
  • ElementType.METHOD: Method.
  • ElementType.PARAMETER: Parameter.
  • ElementType.CONSTRUCTOR: Constructor.
  • ElementType.LOCAL_VARIABLE: Local variable.
  • ElementType.ANNOTATION_TYPE: Annotation type.
  • ElementType.PACKAGE: Package.
2. Using Custom Annotations

You can apply your custom annotations to the appropriate elements in your code. For example:

public class ExampleService {

    @LogExecutionTime
    public void serve() {
        // Method implementation
    }
}
3. Processing Custom Annotations

Processing annotations typically involves using reflection or annotation processors. Here’s how you can process the @LogExecutionTime annotation using reflection:

import java.lang.reflect.Method;

public class AnnotationProcessor {

    public static void processAnnotations(Object object) throws Exception {
        Class<?> clazz = object.getClass();
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.isAnnotationPresent(LogExecutionTime.class)) {
                long start = System.currentTimeMillis();
                method.invoke(object);
                long end = System.currentTimeMillis();
                System.out.println("Execution time of " + method.getName() + " is " + (end - start) + "ms");
            }
        }
    }
}

Job Offers

Job Offers


    Senior Android Developer

    SumUp
    Berlin
    • Full Time
    apply now

    Senior Android Engineer

    Carly Solutions GmbH
    Munich
    • Full Time
    apply now

OUR VIDEO RECOMMENDATION

Jobs

4. Example Usage
public class Main {

    public static void main(String[] args) throws Exception {
        ExampleService service = new ExampleService();
        AnnotationProcessor.processAnnotations(service);
    }
}

When processAnnotations is called, it will find methods annotated with @LogExecutionTime and print their execution time.

5. Advanced Use Cases

Custom annotations can be powerful tools for various advanced use cases, such as:

a. Dependency Injection:

Annotations can be used to mark dependencies for injection.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Inject {
}

public class MyActivity extends Activity {

    @Inject
    MyService myService;
}
b. Code Generation:

Annotation Processors (APT) can be used to generate code at compile-time.

@SupportedAnnotationTypes("com.example.MyAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyAnnotationProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
            // Generate code based on the annotated elements
        }
        return true;
    }
}
c. Validation:

Annotations can be used for validating method parameters, fields, etc.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface NotNull {
}

public class Validator {

    public static void validate(Object object) throws IllegalAccessException {
        for (Field field : object.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(NotNull.class) && field.get(object) == null) {
                throw new IllegalArgumentException(field.getName() + " should not be null");
            }
        }
    }
}
6. Integrating with Libraries

Custom annotations can be integrated with libraries like Dagger for dependency injection, Retrofit for networking, or Room for database operations.

// Dagger example
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ForApplication {
}

@Module
public class AppModule {
    @Provides
    @ForApplication
    Context provideApplicationContext(Application application) {
        return application.getApplicationContext();
    }
}

By using custom annotations effectively, you can make your Android code more modular, maintainable, and easier to understand.

This article is previously published on proandroiddev.com

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
Using annotations in Kotlin has some nuances that are useful to know
READ MORE
blog
One of the latest trends in UI design is blurring the background content behind the foreground elements. This creates a sense of depth, transparency, and focus,…
READ MORE
blog
Now that Android Studio Iguana is out and stable, I wanted to write about…
READ MORE
blog
The suspension capability is the most essential feature upon which all other Kotlin Coroutines…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu