Android

AndroidAnnotations: Understanding the bean lifecycle

Learn the basics about the bean lifecycle to gain a deeper understanding of the inner workings of the AndroidAnnotations framework.

android_thumb_090613.jpg
AndroidAnnotations eliminates the boilerplate code that is common in Android projects by replacing it with annotations. Since there is less code to write and maintain, this helps to speed development and improve maintainability.

In my previous TechRepublic article, I covered the basics of how to set up an AndroidAnnotations project and use general annotations. In this installment, I will cover the core concepts of the bean lifecycle and explain how to use those concepts to develop more complex applications.

Lifecycle management

An important concept within any dependency injection framework is lifecycle management. Understanding the scope of components, as well as how to hook into any events within that scope, is key to developing more complex applications. AndroidAnnotations provides two scoping options for @EBean components: default scope and singleton scope.

The default scope creates a new bean each time the bean is injected. This is the most common case, as it ensures state-sharing is limited to the dependent component. The singleton scope is reminiscent of the well-known Singleton pattern. There is only one @EBean instance for the scope of the entire App in this case. This scope is useful when a component is either expensive to create (e.g., requires parsing a complex configuration file) or requires extensive memory allocation (e.g., a caching component).

To define the scope of an @EBean as singleton, annotate the component as follows:

@EBean(scope = Scope.Singleton)
public class CalculatorBean {
  // ... ...
}

Be aware that there are certain injection limitations with a singleton Bean. For example, injection of views or the application context is disallowed, as these components have a scope that is more limited than the singleton scope.

Lifecycle hooks

The @AfterInject annotation allows you to execute code directly after dependencies are injected into an @EBean. In general, class initialization logic is performed in the constructor. In cases where dependencies are necessary to perform that initialization logic, the @AfterInject annotation is useful.

@EBean
public class CalculatorBean {
  @Bean
  private Calculator calculator;

  @AfterInject
  public void initMemory() {
    // retrieve and set the last memory record into the 
    // calculator bean
  }
	
  // ... ...
}

As you can see in the example above, we initialize the calculator memory once the calculator bean has been injected.

Similarly, the @AfterViews annotation allows code to be executed directly after the injection of view components. This is useful when views need some type of initial setup prior to user interaction.

@EActivity(R.layout.activity_calculator)
public class CalculatorActivity extends Activity {
  // ... ...

  @ViewById Button memoryRecall;

  @Bean CalculatorService calculatorService;
  @Bean Calculator calculator;
	
  @AfterViews
  public void initMemoryRecall() {
    if(calculator.hasMemory()) {
      memoryRecall.getBackground()
        .setColorFilter(Color.BLUE, Mode.MULTIPLY);
    }
  }
	
  // ... ...
}

Notice that we modify the color of the memory recall Button based on whether any memory data has been retrieved by the CalculatorService.

To deepen your understanding of the @AfterInject and @AfterViews method, you can review the generated underscore class (e.g., CalculatorActivity_.java) to see exactly where the annotated methods are being invoked.

Method tracing

To see when our lifecycle methods are executed, we can use the @Trace annotation.  This is also useful when debugging or tracking down performance bottlenecks by tracing method execution to determine the location of the root cause.

@EActivity(R.layout.activity_calculator)
public class CalculatorActivity extends Activity {
  private final static String TAG = "Calculator";

  // ... ...

  @Click
  @AfterViews
  @Trace(level = Log.INFO, tag = TAG)
  public void initMemoryRecall() {
    if(calculator.hasMemory()) {
      memoryRecall.getBackground()
        .setColorFilter(Color.BLUE, Mode.MULTIPLY);
    }
  }
	
  // ... ...
}

By adding this annotation at the method level, you will see log results like the following:

I/CalculatorActivity(  302): Entering [void initMemory() ]
I/CalculatorActivity(  302): Exiting [void initMemory() ], duration in ms: 42

As you can see, a Log level is specified along with a Tag for identifying the log statement. The duration of the method execution is output by the exit statement; this provides visibility into which methods are suspects for performance tuning.

Experiment on your own

Now that you understand the basics of the bean lifecycle, try your own use cases to experiment on your own. This will help drive a deeper understanding of the inner workings of the AndroidAnnotations framework.

About

Jacob Orshalick is a software consultant, open source developer, speaker, and author. He is the owner of solutionsfit and co-author of the best-selling Seam Framework: Experience the Evolution of Java EE. His software development experience spans the...

2 comments
javaContractor
javaContractor

Actually, I just found where the Scope class is hiding. It is now underneath the EBean class itself (in 3.0.1):


import org.androidannotations.annotations.EBean.Scope

javaContractor
javaContractor

Hi - excellent post. Just starting to use Android Annotations here, version 3.0.1. I noticed something odd though:


- in Android Annotations 2.5, the class package appears to be com.googlecode.androidannotations.api and com.googlecode.androidannotations.annotations. The "Scope" class was in the first package.


- but now, in Android Annotations 3.0.1, the class package is either org.androidannotations.api or org.androidannotations.annotations. Unfortunately, the "Scope" class does not appear to be in the first package anymore. I searched everywhere in the two new "org" packages: it looks like "Scope" is gone!


I can't find any reference to this change anywhere on the web. Do you know what happened to it? How can we set the scope on our EBeans with 3.0.1?


Thanks!

Editor's Picks