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.

AndroidAnnotations heavily utilizes dependency injection. This design pattern not only allows you to eliminate boilerplate, it also provides the added benefit of introducing consistency into a code base. This can be a significant advantage when new developers are introduced to a code base.

The following example demonstrates a basic Android app developed
using AndroidAnnotations. The first step will be to show the basic application
without the use of AndroidAnnotations. Then I will show the application with AndroidAnnotations, and I will make enhancements using various annotations. Follow along with the step-by-step tutorial,
or download and import the project in its entirety.

The basic Android app

For the purpose of our example, we will use a very simple layout.
In the /res/ layout/activity_calculator.xml file, we create a linear layout.
The layout contains two EditTexts that allow the user to input two
numbers. The next element is a Button that will perform the addition when
clicked. The last element is a TextView that displays the result of the
addition operation.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_gravity="left"
android:gravity="left"
tools:context=".Calculator" >

<EditText
android:id="@+id/firstNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:ems="10"
android:inputType="number">
<requestFocus />
</EditText>

<EditText
android:id="@+id/secondNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number" />

<Button
android:id="@+id/addButton"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:layout_marginLeft="30dip"
android:text="Add" />

<TextView
android:id="@+id/total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="70dip" />

</LinearLayout>

In the /src directory of the project, we create an activity that
handles rendering our layout and registering an OnClickListener with the
addButton. The OnClickListener calculates the total of the two numbers the user
input and renders the total directly below the Add button.

public class Calculator extends Activity {
private EditText firstNumber;
private EditText secondNumber;
private TextView total;
private Button addButton;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calculator);

firstNumber = (EditText) findViewById(R.id.firstNumber);
secondNumber = (EditText) findViewById(R.id.secondNumber);
addButton = (Button) findViewById(R.id.addButton);
total = (TextView) findViewById(R.id.total);

addButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Integer totalResult =
getFirstNumberResult() + getSecondNumberResult();
total.setText("Total = " + Integer.toString(totalResult));
}
});
}

private int getFirstNumberResult() {
return Integer.parseInt(firstNumber.getText().toString());
}

private int getSecondNumberResult() {
return Integer.parseInt(secondNumber.getText().toString());
}
}

The basic app with AndroidAnnotations

Now we want to convert the example to AndroidAnnotations and
eliminate the boilerplate code found in the onCreate method. If you are creating your
own project, follow the instructions on GitHub to set up the project. The provided
example works in Eclipse. The converted
Calculator class is shown below.

@EActivity(R.layout.activity_calculator)
public class Calculator extends Activity {
@ViewById EditText firstNumber;
@ViewById EditText secondNumber;
@ViewById TextView total;

@Click
public void addButton() {
Integer totalResult = getFirstNumberResult() + getSecondNumberResult();
total.setText("Total = " + Integer.toString(totalResult));
}

private Integer getFirstNumberResult() {
return Integer.parseInt(firstNumber.getText().toString());
}

private Integer getSecondNumberResult() {
return Integer.parseInt(secondNumber.getText().toString());
}
}

We have eliminated the need for the onCreate
method; the behavior associated with
this method is now divided between several annotations. The @EActivity annotation on the class
specifies that AndroidAnnotations should apply annotation-based behavior to
this class. The view id that is passed
to the @EActivity annotation defines the layout associated with the activity
when it is activated; this avoids the
need for a call to setContentView.

The @ViewById annotation injects the view object with the
attribute name; this avoids the need to
retrieve those view objects manually. In
the example, the @ViewById applied to firstNumber will set that attribute to the
EditText with the firstNumber id. The
@Click annotation applies an OnClickListener to the view object with the same
id as the method name. In the example,
the @Click annotation on the Add button ensures the method will execute
when the Add button is clicked.

AndroidAnnotations provides the dependency injection behavior
through code generation. Any class that
is annotated for processing will have a corresponding generated class. The generated classes can be recognized by
their name, as they always end with an underscore. In the example, Calculator.java has a
corresponding Calculator_.java. You can
always review these generated classes to analyze the code that is being created
by AndroidAnnotations. This can be useful
when debugging.

Due to the code generation behavior, it is necessary to reference
the corresponding generated Activity class in the AndroidManifest.xml file.

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name="com.solutionsfit.calculator.Calculator_"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

We reference Calculator_ instead of
Calculator, because this ensures the
AndroidAnnotations behavior will be applied to the Calculator class during
execution.

Extending the basic app
with AndroidAnnotations

A common requirement in an Android app is retrieving a string
from strings.xml or an integer from an error_codes.xml file. These types of resources can be easily
injected using the @StringRes and @IntegerRes annotations, respectively. Let’s apply this to our example by extracting
the Total string to the strings.xml
file.

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!– … –>
<string name="total_label">Total</string>
</resources>

Now
we can refactor the addButton method to use the injected totalLabel.

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

@StringRes String totalLabel;

@Click
public void addButton() {
Integer totalResult = calculateTotal();
total.setText(totalLabel + " = " + Integer.toString(totalResult));
}
}

We can also use annotations in a class that is not a standard
Android component; this allows certain
reusable operations or behavior to be refactored into injectable
components. While it is a bit contrived
for our example, we could break out the addition behavior into a
CalculatorBean.

@EBean
public class CalculatorBean {
public Integer add(Integer num1, Integer num2) {
return num1 + num2;
}
}

Similar to the @EActivity annotation, the @EBean annotation informs AndroidAnnotations that the class should be processed for annotated
behavior; it also makes the class
available for injection into another annotated class. We can now inject CalculatorBean within the
Calculator class and invoke the add method when the Add button is clicked.

@Bean CalculatorBean calculatorBean;

@Click
public void addButton() {
Integer totalResult =
calculatorBean.add(getFirstNumberResult(), getSecondNumberResult());
total.setText(totalLabel + " = " + Integer.toString(totalResult));
}

The @Bean always corresponds to some @EBean class that is to be
injected. The @EBean annotated class
supports the same types of behavior that an annotated Android component
would. To demonstrate this, let’s add a divide
button to activity_calculator.xml.

<Button
android:id="@+id/divideButton"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:layout_marginLeft="30dip"
android:text="Divide" />

Now we can add the expected divide behavior to the
CalculatorBean.

@EBean
public class CalculatorBean {
@RootContext Context context;

@StringRes String divideByZeroMessage;

// … …
public Integer divide(Integer num1, Integer num2) {
if (num2 == 0) {
showMessage(divideByZeroMessage);
return null;
}

return num1 / num2;
}

@UiThread
public void showMessage(String message) {
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
}
}

Notice the use of new annotations. Divide by zero must be handled to avoid an
overflow condition. The showMessage
method displays a Toast message to notify the user that the operation could not
be performed. The @UiThread annotation
ensures that the method executes on the UI thread. When adding UI behavior to @Bean classes, it
may be necessary to specify @UiThread if the method could be invoked in a
background thread.

The @RootContext annotation allows for the injection of the
current Context. This annotation can
also be used to inject the Activity if the root context is an Activity, or a
Service if the root context is a Service. Let’s invoke the divide method from the Calculator activity.

@StringRes String undefinedLabel;

@Click
public void divideButton() {
handleDivide();
}

@Background
public void handleDivide() {
showDivideResult(
calculatorBean.divide(getFirstNumberResult(), getSecondNumberResult()));
}

@UiThread
protected void showDivideResult(Integer divideResult) {
if(divideResult == null) {
total.setText(totalLabel + " = " + undefinedLabel);
} else {
total.setText(totalLabel + " = " + Integer.toString(divideResult));
}
}

Here the division is handled on a background thread by using the
@Background annotation. While it may not
be necessary in our case, this is useful when a process may execute for an
extended period of time.

Try it and see for yourself

Now that you’ve experienced the power of AndroidAnnotations,
give it a try. It may help you get your
next Android app to market before the competition.