Slide 1

Slide 1 text

Modern Android app library stack Tomáš Kypta #MobCon

Slide 2

Slide 2 text

Getting into Android

Slide 3

Slide 3 text

Q: “How do I get the data from the server?”

Slide 4

Slide 4 text

A: “Use AsyncTask!” The old school approach™

Slide 5

Slide 5 text

public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener { public void onClick(View view) { new DownloadTask().execute(inputString); } }); } private class DownloadTask extends AsyncTask { @Override protected String doInBackground(String... params) { // download some data } @Override protected void onPostExecute(String result) { TextView txt = (TextView) findViewById(R.id.text); txt.setText(result); } } }

Slide 6

Slide 6 text

Old school Android apps • business logic in activities • with all the bad stuff such as networking • and memory leaks • and crashes

Slide 7

Slide 7 text

Modern Android apps • use cleaner architectures • MVP, MVVM, MVI • use libraries heavily • use tests

Slide 8

Slide 8 text

Libraries • save time and work • simplify API • back-port new APIs to older Android version

Slide 9

Slide 9 text

Ideal Android Library • “perform one task and perform it well” • easy to use • open-source • easily available • through a remote Maven repository

Slide 10

Slide 10 text

Ideal Android Library • doesn’t eat too much resources • doesn’t require too many permissions • behave nicely when crashing

Slide 11

Slide 11 text

“I wan’t my app to work on Android from version 4.1.” 98% of Android devices!

Slide 12

Slide 12 text

Support libraries • available through Android SDK • backport newer Android APIs • helper classes • debugging, testing, utilities

Slide 13

Slide 13 text

Support libraries • AsyncTaskLoader • com.android.support:support-core-utils:25.3.0 • ViewPager • com.android.support:support-core-ui:25.3.0 • support fragments • com.android.support:support-fragment:25.3.0

Slide 14

Slide 14 text

Support libraries • AppCompatActivity, ActionBar • com.android.support:appcompat-v7:25.3.0 • RecyclerView • com.android.support:recyclerview-v7:25.3.0 • CardView • com.android.support:cardview-v7:25.3.0

Slide 15

Slide 15 text

Support libraries • com.android.support:support-annotations:25.3.0 • useful annotations • StringRes, IntDef, Nullable, UiThread, WorkerThread, CallSuper, VisibleForTesting, … • com.android.support:design:25.3.0 • Material design

Slide 16

Slide 16 text

Support libraries • Having more than 64k methods? • And supporting Android prior 5.0? • com.android.support:multidex:1.0.1

Slide 17

Slide 17 text

“This dependency injection thing sounds useful.”

Slide 18

Slide 18 text

Dagger 2 • dependency injection framework for Android and Java • avoids reflection • uses compile-time generated code

Slide 19

Slide 19 text

Dagger 2 public class SimpleGameProvider { private ApiProvider mApiProvider; private StorageProvider mStorageProvider; @Inject public SimpleProvider(ApiProvider apiProvider, StorageProvider storageProvider) { mApiProvider = apiProvider; mStorageProvider = storageProvider; } public void doSomething() { // … } }

Slide 20

Slide 20 text

Dagger 2 @Module public class AppModule { private Context mApplicationContext; public AppModule(Context applicationContext) { mApplicationContext = applicationContext; } @Singleton @Provides protected OtherProvider provideTheOther(Context context) { return new OtherProvider(context); } }

Slide 21

Slide 21 text

Dagger 2 @Singleton @Component(modules = {AppModule.class}) public interface AppComponent { void inject(MainActivity activity); }

Slide 22

Slide 22 text

Dagger 2 public class MainActivity extends AppCompatActivity { @Inject SimpleProvider mSimpleProvider; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ((MyApplication) getApplication()).getAppComponent().inject(this); // and now we can use mSimpleProvider } }

Slide 23

Slide 23 text

“My server has this REST API…”

Slide 24

Slide 24 text

Retrofit • simple REST client for Android and Java • annotation-based API • type-safe • Rx compatible

Slide 25

Slide 25 text

Retrofit public interface GitHubApi { @GET("/users/{username}") User getUser(@Path("username") String username); @GET("/users/{username}/repos") List getUserRepos(@Path("username") String username); @POST("/orgs/{org}/repos") RepoCreationResponse createRepoInOrganization( @Path("org") String organization, @Body RepoCreationRequest request); }

Slide 26

Slide 26 text

Retrofit RestAdapter adapter = new RestAdapter.Builder() .setEndpoint(GITHUB_API_URL) .setRequestInterceptor(new RequestInterceptor() { @Override public void intercept(RequestFacade request) { request.addHeader("Accept", "application/vnd.github.v3+json"); } }) .setLogLevel(RestAdapter.LogLevel.BASIC) .build(); GitHubApi gitHubApi = adapter.create(GitHubApi.class);

Slide 27

Slide 27 text

“And my server has this fancy new features…”

Slide 28

Slide 28 text

OkHttp • an efficient HTTP client for Android and Java • requests can be easily customized • support for HTTP/2 • connection pooling • transparent GZIP • response caching

Slide 29

Slide 29 text

OkHttp OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(url) .build(); Response response = client.newCall(request).execute(); return response.body().string();

Slide 30

Slide 30 text

OkHttp • Works out of the box with the latest Retrofit!

Slide 31

Slide 31 text

“The server returns 400. What’s wrong?”

Slide 32

Slide 32 text

Stetho • A debug bridge • hooks into Chrome Developer Tools

Slide 33

Slide 33 text

Stetho • network inspection • database inspection • view hierarchy • dumpapp system allowing custom plugins • command-line interface for communication with the plugins

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

Stetho public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Stetho.initializeWithDefaults(this); } }

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

Stetho OkHttpClient okHttpClient = new OkHttpClient.Builder() .addNetworkInterceptor(new StethoInterceptor()) .build();

Slide 38

Slide 38 text

“Why I’m getting this OutOfMemoryError?”

Slide 39

Slide 39 text

LeakCanary • memory leak detection library • notifies about memory leaks during app development

Slide 40

Slide 40 text

LeakCanary dependencies { debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' }

Slide 41

Slide 41 text

“How to display this remote product image?”

Slide 42

Slide 42 text

Image loaders • tons of libs • Universal Image Loader • Picasso • Glide

Slide 43

Slide 43 text

Picasso Picasso.with(context) .load(url) .resize(50, 50) .centerCrop() .placeholder(R.drawable.placeholder) .error(R.drawable.error) .into(vImageView);

Slide 44

Slide 44 text

“How can I notify that class?“ “There has to be some way without refactoring the whole thing!”

Slide 45

Slide 45 text

Event bus • for communication between decoupled parts of an app • EventBus

Slide 46

Slide 46 text

EventBus • events • subscribers • register and unregister • post events public static class MessageEvent { /* fields if needed */ } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) {/* handle event */}; EventBus.getDefault().register(this); EventBus.getDefault().unregister(this); EventBus.getDefault().post(new MessageEvent());

Slide 47

Slide 47 text

“How do I get the data from the server?” “And I have to combine couple of sources.”

Slide 48

Slide 48 text

RxJava • general Java library • reactive programming • push concept • composable data flow

Slide 49

Slide 49 text

RxJava • useful for simple async processing • async composition • offers simple chaining of operations on data • eliminates callback hell

Slide 50

Slide 50 text

RxJava • works well with Retrofit • can completely replace event bus libraries • hard to learn • RxJava 1 vs. RxJava 2 • they will coexist for some time

Slide 51

Slide 51 text

RxJava data flow Observable .from(new String[]{"Hello", "Droidcon!"}) creation

Slide 52

Slide 52 text

RxJava data flow Observable .from(new String[]{"Hello", "Droidcon!"}) .map(new Func1() { @Override public String call(String s) { return s.toUpperCase(Locale.getDefault()); } }) creation

Slide 53

Slide 53 text

RxJava data flow Observable .from(new String[]{"Hello", "Droidcon!"}) .map(new Func1() { @Override public String call(String s) { return s.toUpperCase(Locale.getDefault()); } }) .reduce(new Func2() { @Override public String call(String s, String s2) { return s + ' ' + s2; } }) creation transformation

Slide 54

Slide 54 text

RxJava data flow Observable .from(new String[]{"Hello", "Droidcon!"}) .map(new Func1() { @Override public String call(String s) { return s.toUpperCase(Locale.getDefault()); } }) .reduce(new Func2() { @Override public String call(String s, String s2) { return s + ' ' + s2; } }) .subscribe(new Action1() { @Override public void call(String s) { Timber.i(s); } }); creation transformation subscription

Slide 55

Slide 55 text

RxJava data flow with Java 8 creation transformation subscription Observable .from(new String[]{"Hello", "Droidcon!"}) .map(s -> s.toUpperCase(Locale.getDefault())) .reduce((s,s2) -> s + ' ' + s2) .subscribe(s -> Timber.i(s));

Slide 56

Slide 56 text

Other Rx libraries RxAndroid RxBinding RxLifecycle RxNavi SQLBrite RxRelay

Slide 57

Slide 57 text

“This new feature is great! I bet users will love it!”

Slide 58

Slide 58 text

Analytics & crash reporting • Google Analytics • Crashlytics • Firebase

Slide 59

Slide 59 text

“I don’t like this Java language.”

Slide 60

Slide 60 text

Kotlin • not a library • a JVM programming language • “Swift for Android devs"

Slide 61

Slide 61 text

Q: “So all I have to do is to Google for a library to do the thing?”

Slide 62

Slide 62 text

A: “think wisely before adding a new library.”

Slide 63

Slide 63 text

Final thoughts • many potential problems • transitive dependencies • permissions • app size • slow app start • threads • logs

Slide 64

Slide 64 text

Questions?