Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Snow White and the
Seven Dwarfs
Murat Yener
@yenerm
Android
who am I?
-Java, Android, web
-Android Dev @Intel
-Conference Speaker (JavaOne, Devoxx…)
-GDG Istanbul Organizer
-Book Aut...
40%
discount with promo
code
VBK43
when ordering
through
wiley.com
valid until end of
December 2015
Once upon a time…
the princess…
well, the Android
had some problems
after eating an… apple
while waiting for the
prince charming…
can Seven Dwarfs help?
Butterknife
Dagger
Volley / OkHttp / Retrofit
GreenBus / Otto
GreenDAO / Schematic
Priority JobQueue...
Butterknife
Dependency Injection for views and actions
Cleaner code
Simple annotation based usage
Use Nullable to avoid ex...
class ExampleActivity extends Activity {
@Bind(R.id.title) TextView title;
@Bind(R.id.subtitle) TextView subtitle;
@Bind(R...
@Nullable @Bind(R.id.might_not_be_there) TextView mightNotBeThere;
@Nullable @OnClick(R.id.maybe_missing) void onMaybeMiss...
//Simple listener injection
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}
//Mul...
ProGuard Configuration
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewInjector { *...
Dagger
Fast dependency injection
Standard javax.inject (JSR 330)
Make your code easy to test
Compile time code generation ...
@Module + @Provides: mechanism for providing
dependencies.
@Inject: mechanism for requesting dependencies.
@Component: bri...


class CoffeeMaker {

@Inject Heater heater;

@Inject Pump pump;

...

}



@Module

class DripCoffeeModule {

@Provides ...
public @interface Component {

Class<?>[] modules() default {};

Class<?>[] dependencies() default {};

}
public @interfac...
ProGuard Configuration
NONE
OkHttp
Widely used, simple fix for HttpClient
Internal cache
HTTP2 and SPDY support
Uses GZIP
Manual handling of background...
//Client

OkHttpClient client = new OkHttpClient();

//Get URL

String run(String url) throws IOException {

Request reque...
ProGuard Configuration
-keepattributes Signature
-keepattributes *Annotation*
-keep class com.squareup.okhttp.** { *; }
-ke...
Volley
Simplest HttpClient fix for Android
Internal Queue
Internal Cache
Runs in a separate thread
Not good for large downl...
RequestQueue queue = Volley.newRequestQueue(this);


StringRequest stringRequest = new StringRequest(Request.Method.GET, u...
ProGuard Configuration
NONE
Retrofit
REST Client for Java
Generates an implementation of the API
Uses annotation to describe URLs, query params
Object ...




public interface GitHubService {



@Headers("Cache-Control: max-age=640000")

@GET("/users/{user}/repos")

List<Repo>...
-keep class com.squareup.okhttp.** { *; }

-keep interface com.squareup.okhttp.** { *; }

-dontwarn com.squareup.okhttp.**...
GreenRobot EventBus
Dispatches events through a bus
Event Driven
Very easy and clean implementation
Easily transfer data b...
//Custom Event Object
public class SampleEvent {
private String message;
public SampleEvent(String message){
this.message=...
//callee
//geteventbus
eventBus.register(this);
public void onEvent(SampleEvent event) {
textField.setText(event.getMessag...
ProGuard Configuration
-keepclassmembers class ** {
public void onEvent*(**);
}
# Only required if you use AsyncExecutor
-k...
Otto
Event bus
decouple different parts of your application
Communication between components
Uses reflection
compile 'com.s...


Bus bus = new Bus();

bus.post(new AnswerAvailableEvent(42));

bus.register(this);



@Subscribe

public void answerAvai...
-keepclassmembers class ** {
@com.squareup.otto.Subscribe public *;
@com.squareup.otto.Produce public *;
}
GreenDao
from the creators of GreenRobot EventBus
Standard SqLite
No create table… etc
Uses code generation for model and ...
new DaoMaster.DevOpenHelper(this, "notes-db", null);
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
n...
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class ...
Schematic
Automatically generate ContentProviders
Backed by SQLite Database
Can be used w/ Android System
Loaders, SyncAda...


public interface ListColumns {



@DataType(INTEGER) @PrimaryKey @AutoIncrement String _ID = "_id";



@DataType(TEXT) @...
ProGuard Configuration
NONE
Priority JobQueue
Persistent queue for scheduling jobs
Easy to prioritize
Delay job execution
Group jobs for batch executi...
public class PostTweetJob extends Job {

public static final int PRIORITY = 1;



public PostTweetJob(String text) {

supe...
ProGuard Configuration
NONE
Timber
Logger with a small, extensible API
Default behavior: Nothing
Behavior is added through Tree instances.
Install ins...


/** A tree which logs important information for crash reporting. */

private static class CrashReportingTree extends Tim...


public void greetingClicked(Button button) {


Timber.i("A button with ID %s was clicked.", button.getId());

//Do stuff...
ProGuard Configuration
NONE
Hugo
Annotation-triggered method call logging
Generates logging code
Zero effect on non-debug builds.
see next slide
buildscript {

repositories {

mavenCentral()

}



dependencies {

classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1'

}
...


@DebugLog

public String getName(String first, String last) {

SystemClock.sleep(15); // Don't ever really do this!

ret...
ProGuard Configuration
NONE
BONUS
The Prince Charming:
Lambdas on Android
wait, Java 8?!?
Android 5.0 and above use Java 7
but not invokeDynamic
so no Lambdas…
Retrolambda
lambda expressions
method references
try-with-resources statements
limited support for backporting default met...
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'me.tatarka:gradle-retrolambda:3.2.3'
}
}
// Requir...
PROGUARD
-dontwarn java.lang.invoke.*
Android Studio
build.gradle
android {
compileOptions {
sourceCompatibility JavaVersi...
Libraries fix things…
Use them only when you have a (exprected)
problem…
and don’t overuse them…
Conclusion…
@yenerm
murat@muratyener.com
-the end
questions?
Upcoming SlideShare
Loading in …5
×

Android and the Seven Dwarfs from Devox'15

1,050 views

Published on

Android and the Seven Dwarfs from Devox'15
Butterknife
Dagger
Volley / OkHttp / Retrofit
GreenBus / Otto
GreenDAO / Schematic
Priority JobQueue
Timber / Hugo
Retrolambda

Published in: Software
  • Be the first to comment

Android and the Seven Dwarfs from Devox'15

  1. 1. Snow White and the Seven Dwarfs Murat Yener @yenerm Android
  2. 2. who am I? -Java, Android, web -Android Dev @Intel -Conference Speaker (JavaOne, Devoxx…) -GDG Istanbul Organizer -Book Author -Java Champion -GDE on Android
  3. 3. 40% discount with promo code VBK43 when ordering through wiley.com valid until end of December 2015
  4. 4. Once upon a time…
  5. 5. the princess… well, the Android had some problems after eating an… apple while waiting for the prince charming…
  6. 6. can Seven Dwarfs help? Butterknife Dagger Volley / OkHttp / Retrofit GreenBus / Otto GreenDAO / Schematic Priority JobQueue Timber / Hugo
  7. 7. Butterknife Dependency Injection for views and actions Cleaner code Simple annotation based usage Use Nullable to avoid exceptions Based on compile time code generation compile ‘com.jakewharton:butterknife:7.0.1’
  8. 8. class ExampleActivity extends Activity { @Bind(R.id.title) TextView title; @Bind(R.id.subtitle) TextView subtitle; @Bind(R.id.footer) TextView footer; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ButterKnife.bind(this); // TODO Use fields... } }
  9. 9. @Nullable @Bind(R.id.might_not_be_there) TextView mightNotBeThere; @Nullable @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() { // TODO ... }
  10. 10. //Simple listener injection @OnClick(R.id.submit) public void submit(View view) { // TODO submit data to server... } //Multi listener @OnClick({ R.id.door1, R.id.door2, R.id.door3 }) public void pickDoor(DoorView door) { if (door.hasPrizeBehind()) { Toast.makeText(this, "You win!", LENGTH_SHORT).show(); } else { Toast.makeText(this, "Try again", LENGTH_SHORT).show(); } }
  11. 11. ProGuard Configuration -keep class butterknife.** { *; } -dontwarn butterknife.internal.** -keep class **$$ViewInjector { *; } -keepclasseswithmembernames class * { @butterknife.* <fields>; } -keepclasseswithmembernames class * { @butterknife.* <methods>; }
  12. 12. Dagger Fast dependency injection Standard javax.inject (JSR 330) Make your code easy to test Compile time code generation (No reflection) Complicated Hard to do for ongoing project compile 'com.google.dagger:dagger:2.0' apt 'com.google.dagger:dagger-compiler:2.0'
  13. 13. @Module + @Provides: mechanism for providing dependencies. @Inject: mechanism for requesting dependencies. @Component: bridge between modules and injections
  14. 14. 
 class CoffeeMaker {
 @Inject Heater heater;
 @Inject Pump pump;
 ...
 }
 
 @Module
 class DripCoffeeModule {
 @Provides Heater provideHeater() {
 return new ElectricHeater();
 }
 
 @Provides Pump providePump(Thermosiphon pump) {
 return pump;
 }
 } @Component(modules = DripCoffeeModule.class)
 interface CoffeeShop {
 CoffeeMaker maker();
 }
  15. 15. public @interface Component {
 Class<?>[] modules() default {};
 Class<?>[] dependencies() default {};
 } public @interface Module {
 Class<?>[] includes() default { };
 } 
 public @interface Provides {
 }
 public @interface MapKey {
 boolean unwrapValue();
 } public interface Lazy<T> {
 T get();
 }
  16. 16. ProGuard Configuration NONE
  17. 17. OkHttp Widely used, simple fix for HttpClient Internal cache HTTP2 and SPDY support Uses GZIP Manual handling of background execution compile 'com.squareup.okhttp:okhttp:2.5.0'
  18. 18. //Client
 OkHttpClient client = new OkHttpClient();
 //Get URL
 String run(String url) throws IOException {
 Request request = new Request.Builder()
 .url(url)
 .build();
 
 Response response = client.newCall(request).execute();
 return response.body().string();
 }
 //Post URL public static final MediaType JSON
 = MediaType.parse("application/json; charset=utf-8");
 
 String post(String url, String json) throws IOException {
 RequestBody body = RequestBody.create(JSON, json);
 Request request = new Request.Builder()
 .url(url)
 .post(body)
 .build();
 Response response = client.newCall(request).execute();
 return response.body().string();
 }
  19. 19. ProGuard Configuration -keepattributes Signature -keepattributes *Annotation* -keep class com.squareup.okhttp.** { *; } -keep interface com.squareup.okhttp.** { *; } -dontwarn com.squareup.okhttp.**
  20. 20. Volley Simplest HttpClient fix for Android Internal Queue Internal Cache Runs in a separate thread Not good for large downloads compile ‘com.mcxiaoke.volley:library-aar:1/0/0’
  21. 21. RequestQueue queue = Volley.newRequestQueue(this); 
 StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
 new Response.Listener<String>() {
 @Override
 public void onResponse(String response) {
 //..
 }
 }, new Response.ErrorListener() {
 @Override
 public void onErrorResponse(VolleyError error) {
 //..
 }
 });
 
 queue.add(stringRequest); //Cancel requests queue.cancelAll(TAG);
  22. 22. ProGuard Configuration NONE
  23. 23. Retrofit REST Client for Java Generates an implementation of the API Uses annotation to describe URLs, query params Object conversion to JSON request body Multipart request body and file upload Only good for REST APIs compile 'com.squareup.retrofit:retrofit:1.9.0'
  24. 24. 
 
 public interface GitHubService {
 
 @Headers("Cache-Control: max-age=640000")
 @GET("/users/{user}/repos")
 List<Repo> listRepos(@Path("user") String user);
 
 @POST("/users/new")
 void createUser(@Body User user, Callback<User> cb);
 } 
 RestAdapter restAdapter = new RestAdapter.Builder()
 .setEndpoint("https://api.github.com")
 .build();
 
 GitHubService service = restAdapter.create(GitHubService.class);
 
 List<Repo> repos = service.listRepos("octocat");
  25. 25. -keep class com.squareup.okhttp.** { *; }
 -keep interface com.squareup.okhttp.** { *; }
 -dontwarn com.squareup.okhttp.** -dontwarn rx.**
 -dontwarn retrofit.**
 -dontwarn okio.**
 -keep class retrofit.** { *; } -keepclasseswithmembers class * {
 @retrofit.http.* <methods>;
 }
  26. 26. GreenRobot EventBus Dispatches events through a bus Event Driven Very easy and clean implementation Easily transfer data between components Uses reflection on runtime compile 'de.greenrobot:eventbus:2.4.0'
  27. 27. //Custom Event Object public class SampleEvent { private String message; public SampleEvent(String message){ this.message=message; } } //Caller //geteventbus eventBus.post(new SampleEvent(“An event”);
  28. 28. //callee //geteventbus eventBus.register(this); public void onEvent(SampleEvent event) { textField.setText(event.getMessage()); };
  29. 29. ProGuard Configuration -keepclassmembers class ** { public void onEvent*(**); } # Only required if you use AsyncExecutor -keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent { public <init>(java.lang.Throwable); } # Don't warn for missing support classes -dontwarn de.greenrobot.event.util.*$Support -dontwarn de.greenrobot.event.util.*$SupportManagerFragment
  30. 30. Otto Event bus decouple different parts of your application Communication between components Uses reflection compile 'com.squareup:otto:1.3.8'
  31. 31. 
 Bus bus = new Bus();
 bus.post(new AnswerAvailableEvent(42));
 bus.register(this);
 
 @Subscribe
 public void answerAvailable(AnswerAvailableEvent event) {
 // TODO: React to the event somehow!
 }
  32. 32. -keepclassmembers class ** { @com.squareup.otto.Subscribe public *; @com.squareup.otto.Produce public *; }
  33. 33. GreenDao from the creators of GreenRobot EventBus Standard SqLite No create table… etc Uses code generation for model and dao compile 'de.greenrobot:greendao'
  34. 34. new DaoMaster.DevOpenHelper(this, "notes-db", null); daoMaster = new DaoMaster(db); daoSession = daoMaster.newSession(); noteDao = daoSession.getNoteDao(); Note note = new Note(null, noteText, comment, new Date()); noteDao.insert(note);
  35. 35. -keepclassmembers class * extends de.greenrobot.dao.AbstractDao { public static java.lang.String TABLENAME; } -keep class **$Properties
  36. 36. Schematic Automatically generate ContentProviders Backed by SQLite Database Can be used w/ Android System Loaders, SyncAdapter, Permissions Harder to use (deal w/ Cursors) apt ‘net.simonvt.schematic:schematic-compiler:0.6.0’ compile ‘net.simonvt.schematic:schematic:0.6.0’
  37. 37. 
 public interface ListColumns {
 
 @DataType(INTEGER) @PrimaryKey @AutoIncrement String _ID = "_id";
 
 @DataType(TEXT) @NotNull String TITLE = "title";
 }
 
 @Database(version = NotesDatabase.VERSION)
 public final class NotesDatabase {
 
 public static final int VERSION = 1;
 
 @Table(ListColumns.class) public static final String LISTS = "lists";
 }
 
 @ContentProvider(authority = NotesProvider.AUTHORITY, database = NotesDatabase.class)
 public final class NotesProvider {
 
 public static final String AUTHORITY = "net.simonvt.schematic.sample.NotesProvider";
 
 @TableEndpoint(table = NotesDatabase.LISTS)
 public static class Lists {
 
 @ContentUri(
 path = Path.LISTS,
 type = "vnd.android.cursor.dir/list",
 defaultSort = ListColumns.TITLE + " ASC")
 public static final Uri LISTS = Uri.parse("content://" + AUTHORITY + "/lists")
 }
 }
  38. 38. ProGuard Configuration NONE
  39. 39. Priority JobQueue Persistent queue for scheduling jobs Easy to prioritize Delay job execution Group jobs for batch execution Not really needed above 5.0 compile 'com.path:android-priority-jobqueue:1.1.2'
  40. 40. public class PostTweetJob extends Job {
 public static final int PRIORITY = 1;
 
 public PostTweetJob(String text) {
 super(new Params(PRIORITY).requireNetwork().persist());
 } 
 @Override
 public void onAdded() {} 
 @Override
 public void onRun() throws Throwable {
 webservice.postTweet(text);
 } 
 @Override
 protected boolean shouldReRunOnThrowable(Throwable throwable) {
 }
 }
  41. 41. ProGuard Configuration NONE
  42. 42. Timber Logger with a small, extensible API Default behavior: Nothing Behavior is added through Tree instances. Install instance by calling Timber.plant() DebugTree: output logs for debug builds and auto tag generation compile 'com.jakewharton.timber:timber:4.1.0'
  43. 43. 
 /** A tree which logs important information for crash reporting. */
 private static class CrashReportingTree extends Timber.Tree {
 @Override protected void log(int priority, String tag, 
 String message, Throwable t) { 
 if (priority == Log.VERBOSE || priority == Log.DEBUG) {
 return;
 }
 
 FakeCrashLibrary.log(priority, tag, message);
 
 if (t != null) {
 if (priority == Log.ERROR) {
 FakeCrashLibrary.logError(t);
 } else if (priority == Log.WARN) {
 FakeCrashLibrary.logWarning(t);
 }
 }
 }
 }
  44. 44. 
 public void greetingClicked(Button button) { 
 Timber.i("A button with ID %s was clicked.", button.getId());
 //Do stuff
 }
  45. 45. ProGuard Configuration NONE
  46. 46. Hugo Annotation-triggered method call logging Generates logging code Zero effect on non-debug builds. see next slide
  47. 47. buildscript {
 repositories {
 mavenCentral()
 }
 
 dependencies {
 classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1'
 }
 }
 
 apply plugin: 'com.android.application'
 apply plugin: 'com.jakewharton.hugo'
  48. 48. 
 @DebugLog
 public String getName(String first, String last) {
 SystemClock.sleep(15); // Don't ever really do this!
 return first + " " + last;
 } 
 V/Example: ⇢ getName(first="Jake", last="Wharton")
 V/Example: ⇠ getName [16ms] = "Jake Wharton"
  49. 49. ProGuard Configuration NONE
  50. 50. BONUS The Prince Charming: Lambdas on Android
  51. 51. wait, Java 8?!? Android 5.0 and above use Java 7 but not invokeDynamic so no Lambdas…
  52. 52. Retrolambda lambda expressions method references try-with-resources statements limited support for backporting default methods and static methods on interfaces
  53. 53. buildscript { repositories { mavenCentral() } dependencies { classpath 'me.tatarka:gradle-retrolambda:3.2.3' } } // Required because retrolambda is on maven central repositories { mavenCentral() } apply plugin: 'com.android.application' //or apply plugin: 'java' apply plugin: ‘me.tatarka.retrolambda' OR plugins { id "me.tatarka.retrolambda" version "3.2.3" }
  54. 54. PROGUARD -dontwarn java.lang.invoke.* Android Studio build.gradle android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }
  55. 55. Libraries fix things… Use them only when you have a (exprected) problem… and don’t overuse them… Conclusion…
  56. 56. @yenerm murat@muratyener.com -the end questions?

×