SlideShare a Scribd company logo
Reactive Functional
Programming with Java 8
on Android N
Shipeng Xu
May 6th 2016
What is Reactive
Programming?
Observer Pattern
An Observable emits items.
A Subscriber consumes those items.
(from RxJava in practice)
Observable Subscriber
Items
Observable & Subscriber
Observable Transform
Items
Subscriber
Observable & Subscriber
Why Reactive
Programming?
Quick example
• Find all png images under a folder
• Load the images into a gallery view
http://gank.io/post/560e15be2dca930e00da1083
new Thread() {
@Override
public void run() {
super.run();
for (Folder folder : folders) {
File[] files = folder.listFiles();
for (File file : files) {
if (file.getName().endsWith(".png")) {
final Bitmap bitmap = getBitmapFromFile(file);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
imageCollectorView.addImage(bitmap);
}
});
}
}
}
}
}.start();
Vanilla Java
http://gank.io/post/560e15be2dca930e00da1083
Observable.from(folders)
.flatMap((folder) -> Observable.from(folder.listFiles()) )
.filter((file) -> file.getName().endsWith(".png") )
.map((file) -> getBitmapFromFile(file) )
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((bitmap) -> imageCollectorView.addImage(bitmap) );
RxJava
Create an Observable
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("World");
subscriber.onCompleted();
}
});
observable.subscribe(subscriber);To subscribe to an observable:
Observable.just("Hello", "World")
Or the shorter version:
Subscriber<String> subscriber = new Subscriber<String>() {
@Override
public void onNext(String s) {
Log.d(tag, "Item: " + s);
}
@Override
public void onCompleted() {
Log.d(tag, "Completed!");
}
@Override
public void onError(Throwable e) {
Log.d(tag, "Error!");
}
};
Subscriber Sample
http://reactivex.io/documentation/observable.html
http://rxmarbles.com/
Reactive Functional Programming with Java 8 on Android N
Demo project
Get started with Java 8 on
Android N
android {
compileSdkVersion 'android-N'
buildToolsVersion "24.0.0 rc1"
defaultConfig {
applicationId "me.billhsu.rxdemo"
minSdkVersion 'N'
targetSdkVersion 'N'
versionCode 1
versionName "1.0"
jackOptions {
enabled true
}
}
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
}
Rx libraries for Android
RxAndroid - Provide a Scheduler that schedules on the main thread or
any given Looper.
RxLifecycle - Lifecycle handling APIs for Android apps using RxJava
RxBinding - RxJava binding APIs for Android's UI widgets.
SqlBrite - A lightweight wrapper around SQLiteOpenHelper and
ContentResolver which introduces reactive stream semantics to queries.
Android-ReactiveLocation - Library that wraps location play services
API boilerplate with a reactive friendly API.
rx-preferences - Reactive SharedPreferences for Android
RxFit - Reactive Fitness API Library for Android
RxWear - Reactive Wearable API Library for Android
RxPermissions - Android runtime permissions powered by RxJava
RxNotification - Easy way to register, remove and manage notifications
using RxJava
Android Scheduler
Schedulers.io()
Schedulers.computation()
Schedulers.newThread()
Schedulers.from(Executor)
Schedulers.immediate()
Schedulers.trampoline()
Observable.just("Hello", "World")
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(/* update UI*/);
REST Responses to
Observables
public interface GitHubApi {
@GET("users/{users}/followers")
Observable<List<GitHubUser>> getFollowers(@Path("users") String user);
@GET("users/{users}")
Observable<GitHubUser> getUser(@Path("users") String user);
}
private void setupRetrofit() {
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(5, TimeUnit.SECONDS);
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl("https://api.github.com/")
.build();
gitHubApi = retrofit.create(GitHubApi.class);
}
https://api.github.com/users/billhsu
RxView.clicks(button).subscribe((a) -> {
button.setClickable(false);
adapter.getGitHubUserList().clear();
adapter.notifyDataSetChanged();
progressBar.setVisibility(View.VISIBLE);
gitHubApi.getFollowers(userName.getText().toString())
.flatMapIterable(users -> users)
.flatMap(user -> gitHubApi.getUser(user.getLogin()))
.filter(user -> !TextUtils.isEmpty(user.getCompany()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
user -> {
adapter.getGitHubUserList().add(user);
adapter.notifyDataSetChanged();
},
error -> {
Toast.makeText(MainActivity.this, error.toString(),
Toast.LENGTH_LONG).show();
button.setClickable(true);
progressBar.setVisibility(View.GONE);
},
() -> {
button.setClickable(true);
progressBar.setVisibility(View.GONE);
});
});
The click stream
Click stream to GitHubUser
Stream
RxView.clicks(button).subscribe((a) -> {
button.setClickable(false);
adapter.getGitHubUserList().clear();
adapter.notifyDataSetChanged();
progressBar.setVisibility(View.VISIBLE);
gitHubApi.getFollowers(userName.getText().toString())
.flatMapIterable(users -> users)
.flatMap(user -> gitHubApi.getUser(user.getLogin()))
.filter(user -> !TextUtils.isEmpty(user.getCompany()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
user -> {
adapter.getGitHubUserList().add(user);
adapter.notifyDataSetChanged();
},
error -> {
Toast.makeText(MainActivity.this, error.toString(),
Toast.LENGTH_LONG).show();
button.setClickable(true);
progressBar.setVisibility(View.GONE);
},
() -> {
button.setClickable(true);
progressBar.setVisibility(View.GONE);
});
});
Subscribe to GitHubUser
Stream
RxView.clicks(button).subscribe((a) -> {
button.setClickable(false);
adapter.getGitHubUserList().clear();
adapter.notifyDataSetChanged();
progressBar.setVisibility(View.VISIBLE);
gitHubApi.getFollowers(userName.getText().toString())
.flatMapIterable(users -> users)
.flatMap(user -> gitHubApi.getUser(user.getLogin()))
.filter(user -> !TextUtils.isEmpty(user.getCompany()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
user -> {
adapter.getGitHubUserList().add(user);
adapter.notifyDataSetChanged();
},
error -> {
Toast.makeText(MainActivity.this, error.toString(),
Toast.LENGTH_LONG).show();
button.setClickable(true);
progressBar.setVisibility(View.GONE);
},
() -> {
button.setClickable(true);
progressBar.setVisibility(View.GONE);
});
});
Summary

More Related Content

Reactive Functional Programming with Java 8 on Android N

  • 1. Reactive Functional Programming with Java 8 on Android N Shipeng Xu May 6th 2016
  • 4. An Observable emits items. A Subscriber consumes those items. (from RxJava in practice) Observable Subscriber Items Observable & Subscriber
  • 7. Quick example • Find all png images under a folder • Load the images into a gallery view
  • 8. http://gank.io/post/560e15be2dca930e00da1083 new Thread() { @Override public void run() { super.run(); for (Folder folder : folders) { File[] files = folder.listFiles(); for (File file : files) { if (file.getName().endsWith(".png")) { final Bitmap bitmap = getBitmapFromFile(file); getActivity().runOnUiThread(new Runnable() { @Override public void run() { imageCollectorView.addImage(bitmap); } }); } } } } }.start(); Vanilla Java
  • 9. http://gank.io/post/560e15be2dca930e00da1083 Observable.from(folders) .flatMap((folder) -> Observable.from(folder.listFiles()) ) .filter((file) -> file.getName().endsWith(".png") ) .map((file) -> getBitmapFromFile(file) ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe((bitmap) -> imageCollectorView.addImage(bitmap) ); RxJava
  • 10. Create an Observable Observable observable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("Hello"); subscriber.onNext("World"); subscriber.onCompleted(); } }); observable.subscribe(subscriber);To subscribe to an observable: Observable.just("Hello", "World") Or the shorter version:
  • 11. Subscriber<String> subscriber = new Subscriber<String>() { @Override public void onNext(String s) { Log.d(tag, "Item: " + s); } @Override public void onCompleted() { Log.d(tag, "Completed!"); } @Override public void onError(Throwable e) { Log.d(tag, "Error!"); } }; Subscriber Sample
  • 15. Get started with Java 8 on Android N android { compileSdkVersion 'android-N' buildToolsVersion "24.0.0 rc1" defaultConfig { applicationId "me.billhsu.rxdemo" minSdkVersion 'N' targetSdkVersion 'N' versionCode 1 versionName "1.0" jackOptions { enabled true } } compileOptions { targetCompatibility 1.8 sourceCompatibility 1.8 } }
  • 16. Rx libraries for Android RxAndroid - Provide a Scheduler that schedules on the main thread or any given Looper. RxLifecycle - Lifecycle handling APIs for Android apps using RxJava RxBinding - RxJava binding APIs for Android's UI widgets. SqlBrite - A lightweight wrapper around SQLiteOpenHelper and ContentResolver which introduces reactive stream semantics to queries. Android-ReactiveLocation - Library that wraps location play services API boilerplate with a reactive friendly API. rx-preferences - Reactive SharedPreferences for Android RxFit - Reactive Fitness API Library for Android RxWear - Reactive Wearable API Library for Android RxPermissions - Android runtime permissions powered by RxJava RxNotification - Easy way to register, remove and manage notifications using RxJava
  • 18. REST Responses to Observables public interface GitHubApi { @GET("users/{users}/followers") Observable<List<GitHubUser>> getFollowers(@Path("users") String user); @GET("users/{users}") Observable<GitHubUser> getUser(@Path("users") String user); } private void setupRetrofit() { OkHttpClient client = new OkHttpClient(); client.setConnectTimeout(5, TimeUnit.SECONDS); Retrofit retrofit = new Retrofit.Builder() .client(client) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl("https://api.github.com/") .build(); gitHubApi = retrofit.create(GitHubApi.class); } https://api.github.com/users/billhsu
  • 19. RxView.clicks(button).subscribe((a) -> { button.setClickable(false); adapter.getGitHubUserList().clear(); adapter.notifyDataSetChanged(); progressBar.setVisibility(View.VISIBLE); gitHubApi.getFollowers(userName.getText().toString()) .flatMapIterable(users -> users) .flatMap(user -> gitHubApi.getUser(user.getLogin())) .filter(user -> !TextUtils.isEmpty(user.getCompany())) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( user -> { adapter.getGitHubUserList().add(user); adapter.notifyDataSetChanged(); }, error -> { Toast.makeText(MainActivity.this, error.toString(), Toast.LENGTH_LONG).show(); button.setClickable(true); progressBar.setVisibility(View.GONE); }, () -> { button.setClickable(true); progressBar.setVisibility(View.GONE); }); }); The click stream
  • 20. Click stream to GitHubUser Stream RxView.clicks(button).subscribe((a) -> { button.setClickable(false); adapter.getGitHubUserList().clear(); adapter.notifyDataSetChanged(); progressBar.setVisibility(View.VISIBLE); gitHubApi.getFollowers(userName.getText().toString()) .flatMapIterable(users -> users) .flatMap(user -> gitHubApi.getUser(user.getLogin())) .filter(user -> !TextUtils.isEmpty(user.getCompany())) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( user -> { adapter.getGitHubUserList().add(user); adapter.notifyDataSetChanged(); }, error -> { Toast.makeText(MainActivity.this, error.toString(), Toast.LENGTH_LONG).show(); button.setClickable(true); progressBar.setVisibility(View.GONE); }, () -> { button.setClickable(true); progressBar.setVisibility(View.GONE); }); });
  • 21. Subscribe to GitHubUser Stream RxView.clicks(button).subscribe((a) -> { button.setClickable(false); adapter.getGitHubUserList().clear(); adapter.notifyDataSetChanged(); progressBar.setVisibility(View.VISIBLE); gitHubApi.getFollowers(userName.getText().toString()) .flatMapIterable(users -> users) .flatMap(user -> gitHubApi.getUser(user.getLogin())) .filter(user -> !TextUtils.isEmpty(user.getCompany())) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( user -> { adapter.getGitHubUserList().add(user); adapter.notifyDataSetChanged(); }, error -> { Toast.makeText(MainActivity.this, error.toString(), Toast.LENGTH_LONG).show(); button.setClickable(true); progressBar.setVisibility(View.GONE); }, () -> { button.setClickable(true); progressBar.setVisibility(View.GONE); }); });