Développer une app Android en 2015

Développer une app Android en 2015

Je développe sur Android depuis 2009, année de naissance de Cupcake, Donut et Eclair et époque où un écran 3.2” et une trackball étaient la norme. Depuis, l’écosystème Android a beaucoup évolué apportant son lot de nouveautés et de challenges. Nous verrons ensemble ce qui se cache derrière une application Android moderne : RxJava, Material Design, RecyclerView... seront notamment de la partie.

Talk donnée au Paris Android User Group le 03/03/2015 chez BlaBlaCar
http://www.meetup.com/Android-Paris/events/220665795/
https://www.youtube.com/watch?v=vJtDozdLEg8

B802469678e56fdee0a95c5e7f27d460?s=128

Florian Mierzejewski

March 03, 2015
Tweet

Transcript

  1. 3.
  2. 6.
  3. 7.
  4. 10.

    OkHttp An HTTP & SPDY client for Android and Java

    applications • Support de HTTP/2 et SPDY • Support de GZIP • Réponses en cache
  5. 11.

    Retrofit A type-safe REST client for Android and Java Utilisation

    d’annotations pour décrire les requêtes HTTP
  6. 19.

    RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint(“https://api-v2launch.trakt.tv”) .build(); ! Movies movies

    = restAdapter.create(Movies.class); ! List<Comment> comments = movies.comments(42, 1, 10);
  7. 24.

    RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint(“https://api-v2launch.trakt.tv”) .setRequestInterceptor(new RequestInterceptor() { @Override

    public void intercept(RequestFacade request) { request.addHeader(“trakt-api-key”, apiKey); } }) .build();
  8. 25.

    @GET("/movies/{id}/comments") List<Comment> comments(/*…*/); ! @GET("/movies/{id}/comments") void comments(/*…*/, Callback<List<Comment>> cb); !

    @GET("/movies/{id}/comments") Response comments(/*…*/); ! @GET("/movies/{id}/comments") Observable<List<Comment>> comments(/*…*/);
  9. 26.

    @GET("/movies/{id}/comments") List<Comment> comments(/*…*/); ! @GET("/movies/{id}/comments") void comments(/*…*/, Callback<List<Comment>> cb); !

    @GET("/movies/{id}/comments") Response comments(/*…*/); ! @GET("/movies/{id}/comments") Observable<List<Comment>> comments(/*…*/);
  10. 27.

    @GET("/movies/{id}/comments") List<Comment> comments(/*…*/); ! @GET("/movies/{id}/comments") void comments(/*…*/, Callback<List<Comment>> cb); !

    @GET("/movies/{id}/comments") Response comments(/*…*/); ! @GET("/movies/{id}/comments") Observable<List<Comment>> comments(/*…*/);
  11. 28.

    @GET("/movies/{id}/comments") List<Comment> comments(/*…*/); ! @GET("/movies/{id}/comments") void comments(/*…*/, Callback<List<Comment>> cb); !

    @GET("/movies/{id}/comments") Response comments(/*…*/); ! @GET("/movies/{id}/comments") Observable<List<Comment>> comments(/*…*/);
  12. 31.

    • Pas de dépendance • Jar < 700KB • Java

    6+ & Android 2.3+ • Support des lambdas de Java 8 • Polyglotte (Scala, Groovy, Clojure et Kotlin) • Exécution synchrone ou asynchrone
  13. 34.

    public interface Observer<T> { ! public abstract void onNext(T t);

    ! public abstract void onCompleted(); ! public abstract void onError(Throwable e); ! }
  14. 35.

    public interface Observer<T> { ! public abstract void onNext(T t);

    ! public abstract void onCompleted(); ! public abstract void onError(Throwable e); ! }
  15. 36.

    public interface Observer<T> { ! public abstract void onNext(T t);

    ! public abstract void onCompleted(); ! public abstract void onError(Throwable e); ! }
  16. 40.

    Observable<Integer> Observable.create(new Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer>

    observer) { try { if (!observer.isUnsubscribed()) { for (int i = 1; i < 5; i++) { observer.onNext(i); } observer.onCompleted(); } } catch (Exception e) { observer.onError(e); } } } );
  17. 43.
  18. 44.
  19. 51.

    Observable.just(1, 2, 3) .subscribe(new Subscriber<Integer>() { @Override public void onNext(Integer

    item) { System.out.println("Next: " + item); } ! @Override public void onError(Throwable error) { System.err.println("Error: " + error.getMessage()); } ! @Override public void onCompleted() { System.out.println("Sequence complete."); } });
  20. 52.

    Observable.just(1, 2, 3) .subscribe(new Subscriber<Integer>() { @Override public void onNext(Integer

    item) { System.out.println("Next: " + item); } ! @Override public void onError(Throwable error) { System.err.println("Error: " + error.getMessage()); } ! @Override public void onCompleted() { System.out.println("Sequence complete."); } });
  21. 53.

    Observable.just(1, 2, 3) .subscribe(new Subscriber<Integer>() { @Override public void onNext(Integer

    item) { System.out.println("Next: " + item); } ! @Override public void onError(Throwable error) { System.err.println("Error: " + error.getMessage()); } ! @Override public void onCompleted() { System.out.println("Sequence complete."); } });
  22. 54.

    > Next: 1 > Next: 2 > Next: 3 >

    Sequence complete.
  23. 56.

    comments(42, 1, 10) .filter(c -> !c.spoiler) .toSortedList((c1, c2) -> Integer.compare(c2.likes,

    c1.likes)) .lift(flattenList()) .take(3) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(myObserver);
  24. 63.

    Pourquoi un ContentProvider ? ! • Système de notification des

    URIs • Reste assez “bas niveau” pour faire ce que l’on veut
  25. 64.

    Ce qui est moins cool ! • Beaucoup de boilerplate

    • Difficile de ne pas faire d’erreurs
  26. 65.

    Schematic à la rescousse ! ! • Génération du ContentProvider

    • Annotations, annotations everywhere • Permet de se concentrer sur le schéma et la bonne gestion des URIs https://github.com/SimonVT/schematic
  27. 66.

    Par contre ! • Très peu de documentation • “La

    documentation c’est le code” • SimonVT/cathode - ProviderSchematic.java https://github.com/SimonVT/schematic
  28. 67.

    public interface MovieColumns { @DataType(INTEGER) @PrimaryKey @AutoIncrement String ID =

    “_id”; /* … */ } ! Supporte également @DefaultValue, @NotNull, @References et @Unique https://github.com/SimonVT/schematic
  29. 68.

    DatabaseX.java ! @Table(MovieColumns.class) public static final String MOVIES = “movies";

    /* … */ ! @ExecOnCreate // indexes, triggers… https://github.com/SimonVT/schematic
  30. 70.

    ProviderX.java - Movies ! @ContentUri( path = Path.MOVIES, type =

    "vnd.android.cursor.dir/movie") public static final Uri CONTENT_URI = buildUri(Path.MOVIES); https://github.com/SimonVT/schematic
  31. 71.

    ProviderX.java - Movies ! @InexactContentUri( path = Path.MOVIES + "/#",

    name = "MOVIE_ID", type = "vnd.android.cursor.item/movie", whereColumn = MovieColumns.ID_TRAKT, pathSegment = 1) public static Uri withId(String traktId) { return buildUri(Path.MOVIES, traktId); } https://github.com/SimonVT/schematic
  32. 73.

    ProviderX.java - Movies ! ! @NotifyUpdate(paths = Path.MOVIES + "/#")

    public static Uri[] notifyUpdate(Context context, Uri uri, String where, String[] whereArgs) { int id = Integer.valueOf(uri.getPathSegments().get(1)); return new Uri[]{CONTENT_URI, withId(id)} } https://github.com/SimonVT/schematic
  33. 74.

    Du Rx dans votre base https://github.com/square/sqlbrite ! • Wrap SQLiteOpenHelper

    • Requêtes en base deviennent des Observables • Supporte les notifications quand une table est modifiée
  34. 77.
  35. 81.
  36. 82.
  37. 85.
  38. 86.
  39. 87.
  40. 88.
  41. 94.

    Ce qui est cool : ! • 3 LayoutManager de

    base • Animations • Modifier l’orientation • Layout depuis le haut ou le bas • Gestion des spans
  42. 95.

    Ce qui l’est moins : ! • Dividers ? •

    Headers / Footers ? • Réécrire les adapters • OnItemClickListener ? • ChoiceModes ?
  43. 96.

    Headers / Footers ! 1. Wrapper l’adapter dans un autre

    2. Gérer les headers / footers à la main 3. Ecrire son propre LayoutManager 4. Padding et Translation
  44. 101.

    Une ligne de code pour supporter tous les types d’écrans

    ! new GridLayoutManager( getActivity(), getResources().getInteger(R.integer.grid_poster_columns)); res/values integers.xml <integer name="grid_poster_columns">3</integer> res/values-land … res/values-sw600dp … …
  45. 102.
  46. 103.
  47. 107.
  48. 108.
  49. 109.