Enhance custom classes - PerfectCarl/androidannotations GitHub Wiki

Since AndroidAnnotations 2.4

Enhancing custom classes

You can use annotations in a class that is not a standard Android component (such as an Activity, a Service).

You just need to annotate it with @EBean:

@EBean
public class MyClass {

}

An @EBean annotated class must have only one constructor. This constructor must either have no parameters, or, as of AndroidAnnotations 2.7, it may have one parameter of type Context.

Injecting enhanced classes

To use this enhanced class in another enhanced class or in an enhanced Android component, use @Bean:

@EBean
public class MyOtherClass {

  @Bean
  MyClass myClass;

}

Notice how you can chain dependencies:

@EActivity
public class MyActivity extends Activity {

  @Bean
  MyOtherClass myOtherClass;

}

You always get a new instance when you use @Bean on a field, unless that bean is a Singleton (see Scopes below).

It is worth noting that the generated subclasses are final, which means that you can't extend generated classes. However, you can extends original classes and generated code will be also generated for the child class. This works for every annotations.

For example the following class will also have myOtherClass injected :

@EActivity
public class MyChildActivity extends MyActivity {

}

Injecting implementations in assignable fields

Since AndroidAnnotations 2.5

If you want to use a dependency in your code through its API (either a superclass or an interface), you can specify the implementation class as the value parameter of the @Bean annotation.

@EActivity
public class MyActivity extends Activity {

    /* A MyImplementation instance will be injected. 
     * MyImplementation must be annotated with @EBean and implement MyInterface.
     */
    @Bean(MyImplementation.class)
    MyInterface myInterface;

}

Does that provide decoupling advantages ? Well, the class still knows about its dependencies implementation, but at least the code using those dependencies has to rely on the API, which is an interesting goal.

Supported annotations

You can use most AA annotations in an @EBean class:

@EBean
public class MyClass {

  @SystemService
  NotificationManager notificationManager;

  @UiThread
  void updateUI() {

  }

}

View related annotations

You can use view related annotations ([@View](Injecting Views), @Click...) in your @EBean class:

@EBean
public class MyClass {

  @ViewById
  TextView myTextView;

  @Click(R.id.myButton)
  void handleButtonClick() {

  }

}

Notice that this will only work if the root Android component that depends on MyClass is an activity with a layout that contains the needed views. Otherwise, myTextView will be null, and handleButtonClick() will never be called.

Injecting the root context

You can inject the root Android component that depends on your @EBean class, using the @RootContext annotation. Please notice that it only gets injected if the context has the right type.

@EBean
public class MyClass {

  @RootContext
  Context context;

  // Only injected if the root context is an activity
  @RootContext
  Activity activity;

  // Only injected if the root context is a service
  @RootContext
  Service service;

  // Only injected if the root context is an instance of MyActivity
  @RootContext
  MyActivity myActivity;

}

In the MyClass instance referenced by the following activity, the service field of MyClass (see above) will be null.

@EActivity
public class MyActivity extends Activity {

  @Bean
  MyClass myClass;

}

Executing code after dependency injection

When the constructor of your @EBean annotated class is called, it's fields have not been injected yet. If you need to execute code at build time, after dependency injection, you should use the @AfterInject annotation on some methods.

@EBean
public class MyClass {

  @SystemService
  NotificationManager notificationManager;

  @Bean
  MyOtherClass dependency;

  public MyClass() {
    // notificationManager and dependency are null
  }

  @AfterInject
  public void doSomethingAfterInjection() {
    // notificationManager and dependency are set
  }

}

Note : If the parent and child classes have @AfterViews annotated methods with the same name, the generated code will be buggy. See issue #591 for more details.

Scopes

Since AndroidAnnotations 2.5

AndroidAnnotations currently support two scopes:

  • the default scope: a new bean instance is created each time a bean must be injected
  • the singleton scope: a new instance of the bean is created the first time it is needed. It is then retained and the same instance is always injected.
@EBean(scope = Scope.Singleton)
public class MySingleton {

}

Caution

  • If your bean has a Singleton scope, it will only keep a reference to the application context (using context.getApplicationContext(). That's because it lives longer than any activity / service, so it shouldn't keep a reference to any such Android component, to avoid memory leaks.
  • We also disable view injection and view event binding in @EBean components with Singleton scope, for the exact same reason (views have a reference to the activity, which may therefore create a leak).