infinite state machine

Android-spezifische Injections mit Roboguice

Introduction

user

Franziska Neumeister

Hat "Media Systems" studiert, entwickelt mobile Apps und will wissen, ob Androiden auch von elektrischen Schafen träumen


LATEST POSTS

Multithreading mit RxJava 18th April, 2016

Testbaren Code schreiben (Teil 1) 23rd April, 2015

Android

Android-spezifische Injections mit Roboguice

Posted on .

Der große Unterschied zwischen der original Guice Bibliothek und Roboguice ist die Möglichkeit auch Abhängigkeiten zu injizieren, die einzigartig für die Android Entwicklung sind. Dazu gehören Werte aus den Resourcen der App wie Text, Animationen, Bilddaten oder Farbwerte, ganze Layouts und View-Objekte aus dem Layout einer Activity oder eines Fragments.

View- und Layout-Injection

Die häufigen Aufrufe von findViewById() in Activities bzw. von getView().findViewById() in Fragmenten können ersetzt werden, indem die Instanz-Variablen der gesuchten View-Objekte mit der Annotation @InjectView() und der richtigen Resource-ID versehen werden:

public class HighscoreActivity extends RoboActivity {
   @InjectView(R.id.score_text) TextView score;
   @Override
   protected void onCreate( Bundle savedState ) {
      super.onCreate(savedState);
      setContentView(R.layout.highscore);
      this.score.setText("00000");
   }
}

Neben View-Objekten lässt sich mit Roboguice auch das Layout einer Activity per Annotation setzen anstatt mit setContentView(). Dafür wird die Activity-Klasse mit der Annotation @ContentView() und der Resource-ID des Layouts versehen. Für Fragmente funktioniert das leider nicht. Hier muss weiterhin der LayoutInflater des Fragments verwendet werden.

@ContentView(R.layout.highscore)
public class HighscoreActivity extends RoboActivity {
}

Resource Injection

Roboguice kann auch Werte aus den Ressourcen eines Android-Projekts injizieren. Damit können z.B. die häufigen Aufrufe von getResources().getString() oder das Durchreichen eines Resource- oder Context-Objekts in Java-Klassen ersetzt werden. Dabei ist es egal, ob es sich um eine String-Ressource, eine Animations-Ressource oder ähnliches handelt. Roboguice liefert den richtigen Typ automatisch. Die Annotation dafür lautet @InjectResource() und benötigt die ID einer Ressource.

public class SomeActivity extends RoboActivity {
   @InjectResource(R.drawable.company_logo) Drawable logo;
   // der Rest der Klasse
}

Injection in Bibliothek-Projekten

Seit Version 14 der Android Developer Tools sind die IDs in der generierten „R“-Klasse von Bibiliothek-Projekten nicht mehr final. Dadurch können sie nicht mehr von den Annotationen für View- und Ressource-Injection benutzt werden. Um trotzdem Roboguice verwenden zu können, kann man statt der Ressourcen-ID Strings übergeben, um das gewünschte Objekt zu erhalten. Für die Ressource-Injection besteht der String aus der Package-ID der Bibliothek, dem Ressourcen-Typ und dem Namen der Ressourcen-ID. Die Annotation sieht dann so aus:

@InjectResource(name="com.myapp:string/some_value_from_lib")
 String someValue;

Für Views lässt sich anstelle einer ID ein gesetzter Tag-Name des gesuchten View-Elements benutzen.

@InjectView(tag="hello") TextField greetingField;

Diese alternativen Techniken haben den Nachteil, dass sie ggf. nicht bei einem Refactoring durch die IDE erfasst werden, anders als wenn man Resource-IDs verwendet. Zum anderen wird erst zur Laufzeit festgestellt, ob die Ressource existiert bzw. ob sich ein Schreibfehler eingeschlichen hat. Bei Resource-IDs wird ein Fehler bereits im Build-Prozess oder direkt von der IDE festgestellt.

Extras Injections

Roboguice hat die Möglichkeit automatisch Werte aus dem Extras Bundle des Intents zu injizieren, mit dem eine Activity oder ein Service gestartet wurde. Dafür gibt es die Annotation @InjectExtras(), die den Schlüssel-Wert, des gesuchten Wertes im Bundle als String benötigt.

this.wishlist = getIntent().getExtras().getStringArrayList("KEY_WISHLIST");

kann ersetzt werden durch:

@InjectExtra("KEY_WISHLIST") private ArrayList<String> wishlist;

Roboguice geht davon aus, dass ein entsprechender Schlüssel und Wert im Bundle existiert, ansonsten wirft es eine Exception. Wenn der Schlüssel nicht immer Teil des Intents ist, kann man die Injektion als optional kennzeichnen

@InjectExtra("SOME_KEY ", optional = true)

Wenn auf jeden Fall ein entsprechender Schlüssel im Bundle existiert, der Wert aber manchmal NULL sein kann, wird das entsprechende Attribut zusätzlich mit der Annotation @Nullable versehen.

@Nullable
@InjectExtra("KEY_WISHLIST")
private ArrayList wishlist;
profile

Franziska Neumeister

Hat "Media Systems" studiert, entwickelt mobile Apps und will wissen, ob Androiden auch von elektrischen Schafen träumen

Navigation