GDG Toulouse - Android Annotations - French

GDG Toulouse - Android Annotations - French

6cd7230b4e87700f07a7bd5d28c54eb3?s=128

Romain Piel

April 24, 2013
Tweet

Transcript

  1. 2.

    Qui suis-je ? • Passionné d’Android depuis 2010 • Développeur

    de nombreuses applications mobiles • Post Office UK, Kiss Kube, Robin for App.net... • Responsable du produit Android chez MPme, Londres
  2. 3.

    Ce soir Android, ce qui alourdit le code Le régime

    AndroidAnnotations Android et les annotations
  3. 5.

    Android, ce qui alourdit le code Les actions sur les

    éléments de l’UI TextView myTextView = (TextView)findViewById(R.id.someId); ((Button)findViewById(R.id.someOtherId)).onClick(new OnClickListener() { @Override public void onClick(View v) { handler.postDelayed(new Runnable() { @Override public void run() { Toast.make("Ah que coucou!", Toast.LENGTH_SHORT).show(); } }, 500); } });
  4. 6.

    Android, ce qui alourdit le code Les AsyncTask class MakeCoffeeTask

    extends AsyncTask<String, Void, Coffee> { @Override protected Coffee doInBackground(String... params) { String brand = params[0]; Boolean withSugar = params[1]; Coffee coffee = makeCoffee(coffeeBrand, withSugar); return coffee; } @Override protected void onPostExecute(Coffee result) { drinkCoffee(result); } }
  5. 7.

    Android, ce qui alourdit le code Et bien d’autres petits

    détails... @Override public void onSaveInstanceState(Bundle bundle) { super.onSaveInstanceState(bundle); bundle.putSerializable("items", items); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null && savedInstanceState.containsKey("items")) { items = ((ArrayList<String> ) savedInstanceState.getSerializable("items")); } } ClipboardManager clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
  6. 9.

    “Le rapport entre le temps consacré a la lecture du

    code et son écriture est bien plus de 10 à 1. Faciliter la lecture, c'est faciliter l'écriture.” Robert C. Martin
  7. 10.
  8. 11.

    @EActivity(R.layout.translate) public class TranslateActivity extends Activity { @ViewById EditText textInput;

    @ViewById(R.id.myTextView) TextView result; @AnimationRes Animation fadeIn; @Click void doTranslate() { translateInBackground(textInput.getText().toString()); } @Background void translateInBackground(String textToTranslate) { String translatedText = callGoogleTranslate(textToTranslate); showResult(translatedText); } @UiThread void showResult(String translatedText) { result.setText(translatedText); result.startAnimation(fadeIn); } } Injection de vue Objectif : Simplifier la vie du développeur Injection de ressource Événements Threads Layout @EActivity(R.layout.translate) public class TranslateActivity extends Activity { @ViewById EditText textInput; @ViewById(R.id.myTextView) TextView result; @AnimationRes Animation fadeIn; @Click void doTranslate() { translateInBackground(textInput.getText().toSt } @Background void translateInBackground(String textToTranslate) String translatedText = callGoogleTranslate(te showResult(translatedText); } @UiThread void showResult(String translatedText) { result.setText(translatedText); result.startAnimation(fadeIn); } }
  9. 12.

    @EActivity(R.layout.translate) public class TranslateActivity extends Activity { @ViewById EditText textInput;

    @ViewById(R.id.myTextView) TextView result; @AnimationRes Animation fadeIn; @Click void doTranslate() { translateInBackground(textInput.getText().toS } @Background void translateInBackground(String textToTranslate) String translatedText = callGoogleTranslate(t showResult(translatedText); } @UiThread void showResult(String translatedText) { result.setText(translatedText); result.startAnimation(fadeIn); Injection de vue Injection de ressource Événements Threads Layout @EActivity(R.layout.translate) public class TranslateActivity extends Activity { @ViewById EditText textInput; @ViewById(R.id.myTextView) TextView result; @AnimationRes Animation fadeIn; @Click void doTranslate() { translateInBackground(textInput.getText().toSt } @Background void translateInBackground(String textToTranslate) String translatedText = callGoogleTranslate(te showResult(translatedText); } @UiThread void showResult(String translatedText) { result.setText(translatedText); result.startAnimation(fadeIn); } }
  10. 13.

    O En tout, plus de 80 annotations: • Amélioration de

    composants • Activity, Service, etc... • Injections • Vues, ressources, dépendances... • Gestion des événements • Simple threading Bonne intégration avec d’autres librairies Objectif : Simplifier la vie du développeur
  11. 14.

    Annotations de base @EActivity(R.layout.translate) public final class TranslateActivity { }

    Les activity sont annotées @EActivity Des annotations existent pour tous les composants classiques : @EService @EReceiver @EApplication @EFragment @EProvider ...
  12. 15.

    Annotations de base Ces classes annotées permettent : • D’améliorer

    les composants de base • Injection de layout • Fullscreen activities, etc... • D’ajouter d’autres annotations sur les attributs et les méthodes
  13. 16.

    Annotations internes - Injections • Injection de vues • Injection

    de ressources • Injection de composants systèmes @ViewById(R.id.myTextView) TextView result; @AnimationRes Animation fadeIn; @SystemService NotificationManager notificationManager;
  14. 17.

    Annotations internes - Injections Les attributs annotés ne peuvent pas

    être utilisés directement dans le constructeur ou le onCreate() @AfterInject : les attributs non-vues sont injectés @AfterViews : les vues sont instanciées @AfterInject public void doSomethingAfterInjection() { } @AfterViews public void updateTextWithDate() { result.setText("Date: " + new Date()); }
  15. 18.

    Annotations internes - Gestion des threads Annotez vos méthodes avec

    @Background et @UiThread Bye AsyncTask! @Background void someBackgroundWork(String aParam, long anotherParam) { } @UiThread void doInUiThread(String result) { }
  16. 19.

    Objets personnalisés Aussi possible d’annoter des classes personnalisées avec @EBean

    : Cette classe peut alors être injectée : @EBean public class MyClass { } @EActivity public class MyActivity extends Activity { @Bean MyClass myObject; }
  17. 21.

    Mais comment ça marche ton truc? Java 6 Annotation Processor

    Génération de code à la compilation Chaque classe annotée aura une sous- classe générée : public final class TranslateActivity_ extends TranslateActivity { ! // Ici sera généré tout le code pas jojo que l'on ne veut pas écrire }
  18. 22.

    Mais comment ça marche ton truc? Configuration de l’IDE (eclipse)

    : 1.Ajouter dans /libs androidannotations-X.X.X-api.jar 2.Ajouter ce jar au build path 3.Ajouter dans un autre dossier /compile-libs le jar androidannotations-X.X.X.jar 4.Dans les project properties : Java Compiler > Annotation Processing Enable annotation processing Java Compiler > Annotation Processing > Factory Path Ajouter le processeur androidannotations-X.X.X.jar
  19. 24.

    Problèmes de performances? Aucun Le travail se fait à la

    compilation. Le runtime n’est donc pas affecté.
  20. 26.

    Retour d’expérience • Au départ assez difficile de se mettre

    dans la logique AndroidAnnotations. • Puis très vite addictif... • Un code beaucoup plus lisible car plus light • Entraîne à modulariser le plus possible son code • Debugging : aucune différence. Le code généré est accessible
  21. 27.

    Retour d’expérience Certaines limites : • Généricité non supportée •

    Très mauvais d’intégrer de l’héritage entre deux classes annotées • Classes internes ne peuvent pas être annotées
  22. 29.

    Roboguice Construit à partir de Google Guice Injection de vues

    et de tout type d’objets. + Injection plus puissante que AndroidAnnotations - Les injections se font au runtime ‣ Moins bonnes performances - Activités doivent hériter de RoboActivity ‣ Problème pour utiliser d’autres librairies
  23. 30.

    Dagger Librairie d’injection de dépendances similaire à Google Guice. Comme

    Roboguice, offre plus d’options sur les injections de dépendances. Les injections se font aussi au runtime. Pas orienté Android mais très light. A fast dependency injector for Android and Java.
  24. 31.

    Butter Knife Librairie très simple pour injecter des vues. Très

    similaire à l’injection de vue d’AndroidAnnotations Fonctionne au runtime class ExampleActivity extends Activity { ! @InjectView(R.id.title) TextView title; ! @InjectView(R.id.subtitle) TextView subtitle; ! @InjectView(R.id.footer) TextView footer; ! @Override public void onCreate(Bundle savedInstanceState) { ! ! super.onCreate(savedInstanceState); ! ! setContentView(R.layout.simple_activity); ! ! Views.inject(this); ! } }
  25. 33.

    Project lombok Librairie Java basée sur les annotations pour simplifier

    au maximum le langage : @AllArgsConstructor public class MyClass { ! @Getter @Setter private int age = 10; ! @Setter(AccessLevel.PROTECTED) private String name; }
  26. 34.

    Otto Librairie Java basé sur des annotations proposant un bus

    d’événements : Otto An enhanced Guava-based event bus with emphasis on Android support. Bus Post Subscribe bus.post(new AnswerAvailableEvent(42)); @Subscribe public void answerAvailable(AnswerAvailableEvent event) { }
  27. 35.

    Retrofit Librairie Java pour implémenter rapidement un client REST. public

    class Client { private static final String API_URL = "https://api.github.com"; class Contributor { String login; int contributions; } interface GitHub { @GET("/repos/{owner}/{repo}/contributors") List<Contributor> contributors( @Name("owner") String owner, @Name("repo") String repo ); } }
  28. 36.

    Roboelectric Librairie orientée Android permettant de faire rapidement des tests

    unitaires. @RunWith(RobolectricTestRunner.class) public class HomeActivityTest { ! private HomeActivity activity; private ImageView pivotalLogo; @Before public void setUp() throws Exception { activity = new HomeActivity(); activity.onCreate(null); pivotalLogo = (ImageView) activity.findViewById(R.id.pivotal_logo); } @Test public void shouldHaveALogo() throws Exception { assertThat(pivotalLogo.getVisibility(), equalTo(View.VISIBLE)); assertThat(shadowOf(pivotalLogo).getResourceId(), equalTo(R.drawable.pivotallabs_logo)); } }