Enhance custom classes - shiraji/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 ofAndroidAnnotations 2.7
, it may have one parameter of typeContext
.
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. In latter case you must annotate the implementation class and not the interface.
@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, andhandleButtonClick()
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
}
}
Warning
If the parent and child classes have
@AfterViews
,@AfterInject
or@AfterExtras
annotated methods with the same name, the generated code will be buggy. See issue #591 for more details.
Also, while there is a guaranteed order about when we call
@AfterViews
,-Inject
or-Extras
annotated methods, there is no guaranteed order for calling each of the methods with the same@AfterXXX
annotation (see issue #810).
Details about when the methods with one of those annotations are called you can find here.
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 (usingcontext.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 withSingleton
scope, for the exact same reason (views have a reference to the activity, which may therefore create a leak).