zu schreiben, weniger Code zu lesen ‣ Open-Source-Projekt, Apache 2.0 ‣ https://github.com/excilys/androidannotations ‣ Ca. 30 Commits/Merges in der letzten Woche ‣ Letztes Release: Juni 2012
ViewGropus optional Deklaration des Layouts ‣ @EBean für eigene Klassen ‣ Contract: Ein Konstruktor, Context- Parameter optional ‣ Optional: Scope ‣ Default: Neue Instanz pro Injektion ‣ Singleton: Nur eine Instanz ‣ Injection nur eingeschränkt @EApplication public class MyApplication extends Application { @Bean MyDatastore dataStore; } @EActivity(R.layout.my_layout) public class MyActivity extends Activity { @App MyApplication app; } @EBean(scope = Scope.Singleton) public class MyBean { @Bean MyDatastore dataStore; }
gesetzt ‣ Kein findViewById mehr, kein getStringExtra mehr, etc. ‣ Automatischer Typecast ‣ Was kann injiziert werden? ‣ Views ‣ Projektressourcen ‣ Intent-Extras ‣ Systemdienste ‣ Fragment-Argumente ‣ Non-Configuration Instances ‣ HTTPS-Client (Key store & trust store aus Ressourcen) ‣ Eigene Objekte ‣ Konsequenz: Entsprechende Instanzvariablen können nicht private sein
aus dem Layout ‣ Ohne ID: Variablenname wird als ID verwendet ‣ @AfterViews ‣ Annotiert Methoden, die nach dem Aufbauen der Views aufgerufen werden @EActivity(R.layout.my_layout) public class MyActivity extends Activity { @ViewById(R.id.input) EditText input; @ViewById // Injects R.id.image ImageView image; @AfterViews void doMyStuff() { input.setOnEditorActionListener(...); } } input = (EditText)findViewById(R.id.text_input) Zum Vergleich:
Setzt Instanz einer @EBean ‣ „Entkopplung“ durch Übergabe des Klassenobjektes ‣ @RootContext (nur @EBeans) ‣ Setzt Context-Objekt einer Bean ‣ View-bezogene Annotations auch für eigene Klassen, wenn der RootContext eine Activity ist ‣ @AfterInject ‣ Annotierte Methode wird nach dependency injection aufgerufen ‣ Aber: Views noch nicht injiziert @EBean public class MyBean { @App MyApplication application; @Bean MyDatastore dataStore; @Bean(MyImplementation.class) MyInterface mySomething; @RootContext Activity activity; @ViewById(R.id.input) EditText input; @AfterInject void init() { } }
aufgerufen ‣ Wahlweise mit View als Parameter oder ohne ‣ Ohne ID: Methodenname wird als ID verwendet ‣ Mehrere Views pro Methode möglich ‣ Nur eine Methode pro View möglich ‣ @LongClick, @Touch ‣ analog @EActivity(R.layout.my_layout) public class MyActivity extends Activity { @Click(R.id.submit) void onSubmit(View pClickedView) { } @Click // When R.id.cancel is clicked void cancel() { } @Click({R.id.this, R.id.that}) void onThisOrThat() { } @LongClick(R.id.foo) void onFooLongClicked() { } @Touch(R.id.bar) void onBarTouched(MotionEvent pEvent) { } } findViewById(R.id.submit).setOnClickListener( new OnClickListener() { public void onClick(View pView) { onSubmit(); } }); Zum Vergleich:
bei onClick bzw. onLongClick aufgerufen ‣ ID des ListViews als Annotations- parameter ‣ Entweder Item-Objekt oder Position (int) als Methodenparameter ‣ @ItemSelect ‣ analog ‣ Flag als zusätzlicher Parameter @EActivity(R.layout.my_list_layout) public class MyActivity extends Activity { @ItemClick(android.R.id.list) void onItemClicked(MyItem pItem) { } @ItemClick(android.R.id.list) void onItemClicked(int pPosition) { } @ItemLongClick(android.R.id.list) void onItemLongClicked(MyItem pItem) { } @ItemSelect void onItemSelected( boolean pSelected, MyItem pItem) { } }
oder Fragment ‣ @OptionsItem ‣ Annotiert Handler zu Menü-Item ‣ Identifikation wieder via ID oder Methodenname ‣ Optional: Boolescher Rückgabewert @EActivity(R.layout.my_layout) @OptionsMenu(R.menu.my_options) public class MyActivity extends Activity { @OptionsItem(R.id.menuShare) void onShareSelected() { } @OptionsItem // When R.id.exit is clicked boolean exit() { return true; } }