Android and the Seven Dwarfs from Devox'15

56
Snow White and the Seven Dwarfs Murat Yener @yenerm Android

Transcript of Android and the Seven Dwarfs from Devox'15

Page 1: Android and the Seven Dwarfs from Devox'15

Snow White and the Seven Dwarfs

Murat Yener @yenerm

Android

Page 2: Android and the Seven Dwarfs from Devox'15

who am I?-Java, Android, web -Android Dev @Intel -Conference Speaker (JavaOne, Devoxx…) -GDG Istanbul Organizer -Book Author -Java Champion -GDE on Android

Page 3: Android and the Seven Dwarfs from Devox'15

40% discount with promo

code

VBK43 when ordering

through wiley.com

valid until end of December 2015

Page 4: Android and the Seven Dwarfs from Devox'15

Once upon a time…

Page 5: Android and the Seven Dwarfs from Devox'15

the princess…well, the Android

had some problems after eating an… apple

while waiting for the prince charming…

Page 6: Android and the Seven Dwarfs from Devox'15

can Seven Dwarfs help? Butterknife

Dagger

Volley / OkHttp / Retrofit

GreenBus / Otto

GreenDAO / Schematic

Priority JobQueue

Timber / Hugo

Page 7: Android and the Seven Dwarfs from Devox'15

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’

Page 8: Android and the Seven Dwarfs from Devox'15

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...

}

}

Page 9: Android and the Seven Dwarfs from Devox'15

@Nullable @Bind(R.id.might_not_be_there) TextView mightNotBeThere;

@Nullable @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {

// TODO ...

}

Page 10: Android and the Seven Dwarfs from Devox'15

//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();

}

}

Page 11: Android and the Seven Dwarfs from Devox'15

ProGuard Configuration

-keep class butterknife.** { *; }

-dontwarn butterknife.internal.**

-keep class **$$ViewInjector { *; }

-keepclasseswithmembernames class * {

@butterknife.* <fields>;

}

-keepclasseswithmembernames class * {

@butterknife.* <methods>;

}

Page 12: Android and the Seven Dwarfs from Devox'15

DaggerFast 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'

Page 13: Android and the Seven Dwarfs from Devox'15

@Module + @Provides: mechanism for providing dependencies.

@Inject: mechanism for requesting dependencies.

@Component: bridge between modules and injections

Page 14: Android and the Seven Dwarfs from Devox'15

class CoffeeMaker { @Inject Heater heater; @Inject Pump pump; ...} @Moduleclass DripCoffeeModule { @Provides Heater provideHeater() { return new ElectricHeater(); } @Provides Pump providePump(Thermosiphon pump) { return pump; }}

@Component(modules = DripCoffeeModule.class) interface CoffeeShop { CoffeeMaker maker();}

Page 15: Android and the Seven Dwarfs from Devox'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();}

Page 16: Android and the Seven Dwarfs from Devox'15

ProGuard Configuration

NONE

Page 17: Android and the Seven Dwarfs from Devox'15

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'

Page 18: Android and the Seven Dwarfs from Devox'15

//ClientOkHttpClient client = new OkHttpClient(); //Get URLString 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(); }

Page 19: Android and the Seven Dwarfs from Devox'15

ProGuard Configuration

-keepattributes Signature

-keepattributes *Annotation*

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

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

-dontwarn com.squareup.okhttp.**

Page 20: Android and the Seven Dwarfs from Devox'15

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’

Page 21: Android and the Seven Dwarfs from Devox'15

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);

Page 22: Android and the Seven Dwarfs from Devox'15

ProGuard Configuration

NONE

Page 23: Android and the Seven Dwarfs from Devox'15

RetrofitREST 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'

Page 24: Android and the Seven Dwarfs from Devox'15

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");

Page 25: Android and the Seven Dwarfs from Devox'15

-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>;}

Page 26: Android and the Seven Dwarfs from Devox'15

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'

Page 27: Android and the Seven Dwarfs from Devox'15

//Custom Event Object

public class SampleEvent {

private String message;

public SampleEvent(String message){

this.message=message;

}

}

//Caller

//geteventbus

eventBus.post(new SampleEvent(“An event”);

Page 28: Android and the Seven Dwarfs from Devox'15

//callee

//geteventbus

eventBus.register(this);

public void onEvent(SampleEvent event) {

textField.setText(event.getMessage());

};

Page 29: Android and the Seven Dwarfs from Devox'15

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

Page 30: Android and the Seven Dwarfs from Devox'15

Otto

Event bus

decouple different parts of your application

Communication between components

Uses reflection

compile 'com.squareup:otto:1.3.8'

Page 31: Android and the Seven Dwarfs from Devox'15

Bus bus = new Bus();bus.post(new AnswerAvailableEvent(42));bus.register(this);

@Subscribepublic void answerAvailable(AnswerAvailableEvent event) { // TODO: React to the event somehow!}

Page 32: Android and the Seven Dwarfs from Devox'15

-keepclassmembers class ** {

@com.squareup.otto.Subscribe public *;

@com.squareup.otto.Produce public *;

}

Page 33: Android and the Seven Dwarfs from Devox'15

GreenDao

from the creators of GreenRobot EventBus

Standard SqLite

No create table… etc

Uses code generation for model and dao

compile 'de.greenrobot:greendao'

Page 34: Android and the Seven Dwarfs from Devox'15

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);

Page 35: Android and the Seven Dwarfs from Devox'15

-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {

public static java.lang.String TABLENAME;

}

-keep class **$Properties

Page 36: Android and the Seven Dwarfs from Devox'15

SchematicAutomatically 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’

Page 37: Android and the Seven Dwarfs from Devox'15

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") }}

Page 38: Android and the Seven Dwarfs from Devox'15

ProGuard Configuration

NONE

Page 39: Android and the Seven Dwarfs from Devox'15

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'

Page 40: Android and the Seven Dwarfs from Devox'15

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) { }}

Page 41: Android and the Seven Dwarfs from Devox'15

ProGuard Configuration

NONE

Page 42: Android and the Seven Dwarfs from Devox'15

TimberLogger 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'

Page 43: Android and the Seven Dwarfs from Devox'15

/** 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); } } }}

Page 44: Android and the Seven Dwarfs from Devox'15

public void greetingClicked(Button button) { Timber.i("A button with ID %s was clicked.", button.getId());

//Do stuff}

Page 45: Android and the Seven Dwarfs from Devox'15

ProGuard Configuration

NONE

Page 46: Android and the Seven Dwarfs from Devox'15

Hugo

Annotation-triggered method call logging

Generates logging code

Zero effect on non-debug builds.

see next slide

Page 47: Android and the Seven Dwarfs from Devox'15

buildscript { repositories { mavenCentral() } dependencies { classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1' } } apply plugin: 'com.android.application'apply plugin: 'com.jakewharton.hugo'

Page 48: Android and the Seven Dwarfs from Devox'15

@DebugLogpublic 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"

Page 49: Android and the Seven Dwarfs from Devox'15

ProGuard Configuration

NONE

Page 50: Android and the Seven Dwarfs from Devox'15

BONUSThe Prince Charming: Lambdas on Android

Page 51: Android and the Seven Dwarfs from Devox'15

wait, Java 8?!?

Android 5.0 and above use Java 7

but not invokeDynamic

so no Lambdas…

Page 52: Android and the Seven Dwarfs from Devox'15

Retrolambda

lambda expressions

method references

try-with-resources statements

limited support for backporting default methods and static methods on interfaces

Page 53: Android and the Seven Dwarfs from Devox'15

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" }

Page 54: Android and the Seven Dwarfs from Devox'15

PROGUARD -dontwarn java.lang.invoke.*

Android Studio build.gradle

android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }

Page 55: Android and the Seven Dwarfs from Devox'15

Libraries fix things…

Use them only when you have a (exprected) problem…

and don’t overuse them…

Conclusion…

Page 56: Android and the Seven Dwarfs from Devox'15

@yenerm [email protected]

-the end questions?