modern android app library stack

Post on 06-Apr-2017

105 Views

Category:

Technology

8 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Modern Android app library stackTomáš Kypta

#MobCon

Getting into Android

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

A: “Use AsyncTask!”

The old school approach™

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<String, Void, String> {

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

Old school Android apps

• business logic in activities

• with all the bad stuff such as networking

• and memory leaks

• and crashes

Modern Android apps

• use cleaner architectures

• MVP, MVVM, MVI

• use libraries heavily

• use tests

Libraries

• save time and work

• simplify API

• back-port new APIs to older Android version

Ideal Android Library• “perform one task and perform it well”

• easy to use

• open-source

• easily available

• through a remote Maven repository

Ideal Android Library

• doesn’t eat too much resources

• doesn’t require too many permissions

• behave nicely when crashing

“I wan’t my app to work on Android from version 4.1.”

98% of Android devices!

Support libraries

• available through Android SDK

• backport newer Android APIs

• helper classes

• debugging, testing, utilities

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

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

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

Support libraries

• Having more than 64k methods?

• And supporting Android prior 5.0?

• com.android.support:multidex:1.0.1

“This dependency injection thing sounds useful.”

Dagger 2

• dependency injection framework for Android and Java

• avoids reflection

• uses compile-time generated code

Dagger 2public class SimpleGameProvider {

private ApiProvider mApiProvider; private StorageProvider mStorageProvider;

@Inject public SimpleProvider(ApiProvider apiProvider, StorageProvider storageProvider) { mApiProvider = apiProvider; mStorageProvider = storageProvider; }

public void doSomething() { // … }}

Dagger 2@Modulepublic class AppModule {

private Context mApplicationContext;

public AppModule(Context applicationContext) { mApplicationContext = applicationContext; }

@Singleton @Provides protected OtherProvider provideTheOther(Context context) { return new OtherProvider(context); }}

Dagger 2

@Singleton@Component(modules = {AppModule.class})public interface AppComponent {

void inject(MainActivity activity);}

Dagger 2public 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 }}

“My server has this REST API…”

Retrofit

• simple REST client for Android and Java

• annotation-based API

• type-safe

• Rx compatible

Retrofitpublic interface GitHubApi { @GET("/users/{username}") User getUser(@Path("username") String username);

@GET("/users/{username}/repos") List<Repo> getUserRepos(@Path("username") String username);

@POST("/orgs/{org}/repos") RepoCreationResponse createRepoInOrganization( @Path("org") String organization, @Body RepoCreationRequest request);}

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

“And my server has this fancy new features…”

OkHttp• an efficient HTTP client for Android and Java

• requests can be easily customized

• support for HTTP/2

• connection pooling

• transparent GZIP

• response caching

OkHttp

OkHttpClient client = new OkHttpClient();Request request = new Request.Builder() .url(url) .build();

Response response = client.newCall(request).execute();return response.body().string();

OkHttp

• Works out of the box with the latest Retrofit!

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

Stetho

• A debug bridge

• hooks into Chrome Developer Tools

Stetho• network inspection

• database inspection

• view hierarchy

• dumpapp system allowing custom plugins

• command-line interface for communication with the plugins

Stetho

public class MyApplication extends Application {

@Override public void onCreate() { super.onCreate();

Stetho.initializeWithDefaults(this); }}

Stetho

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

“Why I’m getting this OutOfMemoryError?”

LeakCanary

• memory leak detection library

• notifies about memory leaks during app development

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

“How to display this remote product image?”

Image loaders

• tons of libs

• Universal Image Loader

• Picasso

• Glide

Picasso

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

“How can I notify that class?“

“There has to be some way without refactoring the whole thing!”

Event bus

• for communication between decoupled parts of an app

• EventBus

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

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

“And I have to combine couple of sources.”

RxJava

• general Java library

• reactive programming

• push concept

• composable data flow

RxJava

• useful for simple async processing

• async composition

• offers simple chaining of operations on data

• eliminates callback hell

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

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

creation

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

creation

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

creation

transformation

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

creation

transformation

subscription

RxJava data flow with Java 8

creationtransformationsubscription

Observable .from(new String[]{"Hello", "Droidcon!"}) .map(s -> s.toUpperCase(Locale.getDefault())) .reduce((s,s2) -> s + ' ' + s2) .subscribe(s -> Timber.i(s));

Other Rx libraries

RxAndroidRxBinding

RxLifecycle

RxNavi

SQLBrite

RxRelay

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

Analytics & crash reporting

• Google Analytics

• Crashlytics

• Firebase

“I don’t like this Java language.”

Kotlin

• not a library

• a JVM programming language

• “Swift for Android devs"

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

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

Final thoughts• many potential problems

• transitive dependencies

• permissions

• app size

• slow app start

• threads

• logs

Questions?

top related