SlideShare a Scribd company logo
, Tips and, Tips and
TricksTricks
RxJavaRxJava
Yaroslav Heriatovych
RxJavaRxJava
BackgroundBackground
ObservableObservable
ObservableObservable
Observables fill the gap by being the ideal implementation of access to
asynchronous sequences of multiple items
single items multiple items
synchronous T getData() Iterable<T> getData()
asynchronous Future<T> getData() Observable<T> getData()
PrimitivesPrimitives
public interface Observer <T> {
void onCompleted();
void onError(java.lang.Throwable throwable);
void onNext(T t);
}
public class Observable <T> {
public final static <T> Observable<T> create(OnSubscribe<T> f)
public rx.Subscription subscribe(rx.Observer<? super T> observer)
// ...
}
public static interface OnSubscribe<T> extends Action1<Subscriber<? super T>> {}
public interface Subscription {
public void unsubscribe();
public boolean isUnsubscribed();
}
public abstract class Subscriber<T> implements Observer<T>, Subscription {...}
Create ObservableCreate Observable
Observable<String> o = Observable.from("a", "b", "c");
Observable<String> o = Observable.just("one object");
Observable<String> o = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("World");
subscriber.onCompleted();
}
});
Transform ObservableTransform Observable
o.skip(10).take(5)
.map(new Func1<String, String>() {
@Override
public String call(String s) {
return s.toUpperCase();
}
})
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.d("rx", s)
}
});
SchedulersSchedulers
o.skip(10).take(5)
.observeOn(Schedulers.computation())
.map(new Func1<String, String>() {
@Override
public String call(String s) {
return s.toUpperCase();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.d("rx", s)
}
});
RxJava: Library,RxJava: Library,
not Framework
LambdaLambda
the new old thingthe new old thing
Used lambdas before it was coolUsed lambdas before it was cool
Observable<Integer> xs = Observable.just(1, 2, 3, 4, 5, 6, 7);
xs.filter(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer x) {
return x % 2 == 0;
}
}).map(new Func1<Integer, Integer>() {
@Override
public Integer call(Integer x) {
return x + 10;
}
}).subscribe(new Action1<Integer>() {
@Override
public void call(Integer x) {
Rx.this.print(x);
}
});
Anonymous classes hide logic behind the
noise
More code - more bugs
MapMap
FilterFilter
Observable<Integer> xs = Observable.just(1, 2, 3, 4, 5, 6, 7);
xs.filter(x -> x % 2 == 0)
.map(x -> x + 10)
.subscribe(x -> print(x));
Less noise
Clear logic
Concise
RetrolambdaRetrolambda
gradle-retrolambdagradle-retrolambda
Once more:
Java8 for android development
Native support in Android Studio
Magic
One more thingOne more thing
It's safer
static class MyActivity extends Activity {
Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String str = "uamobile";
handler.postDelayed(new Runnable() {
@Override
public void run() {
Log.d("Rx", str);
}
}, 10000);
}
}
class MyActivity$1
extends java.lang.Object implements java.lang.Runnable{
final java.lang.String val$str;
final MyActivity this$0;
MyActivity$1(cMyActivity, java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield
5: aload_0
6: aload_2
7: putfield
10: aload_0
11: invokespecial
14: return
public void run();
Code:
0: ldc
2: aload_0
3: getfield
6: invokestatic
9: pop
10: return
}
One more thingOne more thing
It's safer
static class MyActivity extends Activity {
Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String str = "uamobile";
handler.postDelayed(() ->
Log.d("Rx", str), 10000);
}
}
final class MyActivity$$Lambda$1
extends java.lang.Object
implements java.lang.Runnable{
public void run();
Code:
0: aload_0
1: getfield
4: invokestatic
7: return
public static java.lang.Runnable
lambdaFactory$(java.lang.String);
Code:
0: new
3: dup
4: aload_0
5: invokespecial
8: areturn
}
One abstractionOne abstraction
to rule them allto rule them all
final View.OnClickListener clickListener =
new View.OnClickListener() {
@Override
public void onClick(View view) {
//...
}
};
new BroadcastReceiver() {
@Override
public void onReceive(Context context,
Intent intent) {
//...
}
};
com.squareup.okhttp.Callback okCallback =
new com.squareup.okhttp.Callback() {
@Override
public void onFailure(Request request,
IOException e) {
//...
}
@Override
public void onResponse(Response response)
throws IOException {
//...
}
};
Observable<Void> click
Observable<Intent> broadcasts
Observable<Response> responses
ViewObservable.text(editText) //Observable<OnTextChangeEvent>
.map(event -> event.text) //Observable<CharSequence>
.filter(cs -> !TextUtils.isEmpty(cs)) //Observable<CharSequence>
.map(cs -> cs.toString().toUpperCase()) //Observable<String>
.take(5) //Observable<String>
.subscribe(str -> handleString(str)); //Subscription
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence,
int i, int i2, int i3) {}
@Override
public void onTextChanged(CharSequence charSequence,
int i, int i2, int i3) {}
int count = 5;
@Override
public void afterTextChanged(Editable editable) {
if (!TextUtils.isEmpty(editable)) {
String transformed = editable.toString().toUpperCase();
handleString(transformed);
count--;
if (count == 0) {
editText.removeTextChangedListener(this);
}
}
}
});
Events as a streamEvents as a stream
take(n)take(n)
Abstract over event producerAbstract over event producer
Observable<CharSequence> input = ViewObservable.text(editText)
.map(event -> event.text);
input.filter(cs -> !TextUtils.isEmpty(cs))
.map(cs -> cs.toString().toUpperCase())
.take(5)
.subscribe(str -> handleString(str));
Observable<CharSequence> input =
AndroidObservable.fromBroadcast(ctx, intentFilter)
.map(intent -> intent.getStringExtra("magic_str"));
Call call = okHttpClient.newCall(...);
Observable<String> input = executeOkCall(call)
.map(response -> {
try {
return response.body().string();
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.flatMap(bodyString -> Observable.from(bodyString.split("n")))
.observeOn(AndroidSchedulers.mainThread());
flatMapflatMap
public Observable<String> fromOkCall1(Call call){
return Observable.create(subscriber -> {
try {
Response response = call.execute();
subscriber.onNext(response.body().string());
subscriber.onCompleted();
} catch (IOException e) {
subscriber.onError(e);
}
});
}
public Observable<String> fromOkCall2(Call call){
return Observable.create(subscriber -> {
call.enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
subscriber.onError(e);
}
@Override
public void onResponse(Response response) throws IOException {
try {
subscriber.onNext(response.body().string());
subscriber.onCompleted();
} catch (IOException e) {
subscriber.onError(e);
}
}
});
});
}
LazynessLazyness
Observable<String> observable =
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("uamobile");
subscriber.onCompleted();
}
});
Simple (cold) ObservableSimple (cold) Observable
observable.subscribe(new Action1<String>() {
@Override
public void call(String s) {
handleString(s);
}
});
Observable<String> lastNcRead =
mBriefcaseHelper.getBriefcaseObservable()
.flatMap(list -> {
Observable<Briefcase> briefcaseObservable = Observable.from(list);
Observable<String> maxRead = briefcaseObservable
.ofType(NotificationReadBriefcase.class)
.map(b -> b.attrs.version)
.firstOrDefault("0");
Observable<String> maxClear = briefcaseObservable
.ofType(NotificationClearBriefcase.class)
.map(b -> b.attrs.version)
.firstOrDefault("0");
return Observable.zip(
maxRead,
maxClear,
(a, b) -> a.compareTo(b) > 0 ? a : b
);
});
Observable<Boolean> hasNotificationsObservable =
mDatastore.getNotifications()
.switchMap(notifications ->
lastNcRead.flatMap(lastNC ->
Observable.from(notifications)
.takeWhile(n -> n.getId().compareTo(lastNC) > 0)
.isEmpty().map(empty -> !empty)
)
).observeOn(AndroidSchedulers.mainThread());
hasNotificationsObservable
.subscribe(hasNotifications -> view.setEnabled(hasNotifications));
Do nothing
Execute all
above
Cold and lazyCold and lazy
Observable<Integer> cold =
Observable.create(subscriber -> {
int result = new Random().nextInt(50);
subscriber.onNext(result);
subscriber.onCompleted();
});
cold.subscribe(n -> print(n)); //13
cold.subscribe(n -> print(n)); //42 =(
Hot and sharedHot and shared
ConnectableObservable<Integer> cold =
Observable.<Integer>create(subscriber -> {
int result = new Random().nextInt(50);
subscriber.onNext(result);
subscriber.onCompleted();
}).publish();
cold.subscribe(n -> print(n)); //40
cold.subscribe(n -> print(n)); //40
cold.connect();
publish & connectpublish & connect
interface Response {
List<String> getData();
Observable<Response> next();
}
public Observable<Response> apiCall(...) {...}
public Observable<String> loadAll(Observable<Response> source) {
if (source == null) {
return Observable.empty();
} else {
return source.flatMap(resp -> {
List<String> data = resp.getData();
Observable<Response> next = resp.next();
return Observable.concat(
Observable.from(data),
loadAll(next)
);
});
}
}
Observable<String> all = loadAll(apiCall(...))
.filter(str -> str.contains("#uamobile"))
.take(20)
.timeout(1, TimeUnit.MINUTES);
Tip: Use infinite squencesTip: Use infinite squences
ObservableObservable
.empty().empty()
concatconcat
Tip: be careful with evaluation timeTip: be careful with evaluation time
Observable<MyHeavyData> dataObservable =
loadDataFromNetwork()
.timeout(10, TimeUnit.SECONDS)
.onErrorResumeNext(Observable.just(loadDataFromStorage()));
Observable<MyHeavyData> dataObservable =
loadDataFromNetwork()
.timeout(10, TimeUnit.SECONDS)
.onErrorResumeNext(ex -> Observable.just(loadDataFromStorage()));
onErrorResumeNext
timeouttimeout
CancelationCancelation
ProactiveProactive
Observable<Integer> items = Observable.create(subscriber -> {
int i = 0;
while (true) {
if(subscriber.isUnsubscribed()) return;
subscriber.onNext(i++);
}
});
items.take(10).subscribe(x -> print(x));
ReactiveReactive
final LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(ctx);
Observable<Intent> broadcasts = Observable.create(subscriber -> {
final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
subscriber.onNext(intent);
}
};
final Subscription subscription = Subscriptions.create(
() -> localBroadcastManager.unregisterReceiver(broadcastReceiver)
);
subscriber.add(subscription);
localBroadcastManager.registerReceiver(broadcastReceiver, intentFilter);
});
OkHttp exampleOkHttp example
public Observable<String> fromOkCall3(Call call){
return Observable.create(subscriber -> {
subscriber.add(Subscriptions.create(() -> call.cancel()));
call.enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
subscriber.onError(e);
}
@Override
public void onResponse(Response response) throws IOException {
try {
subscriber.onNext(response.body().string());
subscriber.onCompleted();
} catch (IOException e) {
subscriber.onError(e);
}
}
});
});
}
Functional CollectionsFunctional Collections
Right here, in your javaRight here, in your java
Observables can be used to operate
over simple collections
Collection as ObservableCollection as Observable
Build-in operators
No intermediate allocations
Functional style
How to useHow to use
1. Create Observable from Iterable
Observable.from(list)
2. Transform it using build-in operators
.filter(...), .map(...), .flatMap(...)
3. Transform to BlockingObservable and get resut
.toBlocking.toList().single()
.toBlocking.single()
.toBlocking.toIterable()
class GameSession {
String user;
int score;
}
List<Pair<String, Integer>> leaderboard =
Observable.from(gameSessions)
.filter(session -> session.score != 0)
.groupBy(session -> session.user)
.flatMap(groupedSessions ->
groupedSessions.map(session -> session.score)
.reduce(0, (n1, n2) -> n1 + n2)
.map(totalScore ->
Pair.create(groupedSessions.getKey(), totalScore))
)
.take(10)
.toSortedList((pair1, pair2) -> pair2.second.compareTo(pair1.second))
.toBlocking()
.single();
Example: LeaderboardExample: Leaderboard
groupBygroupBy
reducereduce
Questions?Questions?
LinksLinks
https://github.com/ReactiveX/RxJava/wiki
Your Mouse is a Database
Principles of Reactive Programming
Top 7 Tips for RxJava on Android

More Related Content

What's hot (19)

PPTX
How Data Flow analysis works in a static code analyzer
Andrey Karpov
 
PDF
The Ring programming language version 1.6 book - Part 184 of 189
Mahmoud Samir Fayed
 
PDF
GeeCON 2017 - TestContainers. Integration testing without the hassle
Anton Arhipov
 
PDF
JVM Mechanics: Understanding the JIT's Tricks
Doug Hawkins
 
PDF
GMock framework
corehard_by
 
DOCX
Java practical
shweta-sharma99
 
PDF
The Ring programming language version 1.10 book - Part 17 of 212
Mahmoud Samir Fayed
 
PDF
Java_practical_handbook
Manusha Dilan
 
PDF
Bang-Bang, you have been hacked - Yonatan Levin, KolGene
DroidConTLV
 
DOCX
Java PRACTICAL file
RACHIT_GUPTA
 
PDF
The Ring programming language version 1.5.1 book - Part 12 of 180
Mahmoud Samir Fayed
 
DOC
Final JAVA Practical of BCA SEM-5.
Nishan Barot
 
PDF
The Ring programming language version 1.5.4 book - Part 10 of 185
Mahmoud Samir Fayed
 
PDF
The Ring programming language version 1.5.3 book - Part 10 of 184
Mahmoud Samir Fayed
 
PPTX
JavaZone 2014 - goto java;
Martin (高馬丁) Skarsaune
 
PPT
2012 JDays Bad Tests Good Tests
Tomek Kaczanowski
 
PDF
Java Practical File Diploma
mustkeem khan
 
DOC
Advanced Java - Praticals
Fahad Shaikh
 
PDF
Java practical(baca sem v)
mehul patel
 
How Data Flow analysis works in a static code analyzer
Andrey Karpov
 
The Ring programming language version 1.6 book - Part 184 of 189
Mahmoud Samir Fayed
 
GeeCON 2017 - TestContainers. Integration testing without the hassle
Anton Arhipov
 
JVM Mechanics: Understanding the JIT's Tricks
Doug Hawkins
 
GMock framework
corehard_by
 
Java practical
shweta-sharma99
 
The Ring programming language version 1.10 book - Part 17 of 212
Mahmoud Samir Fayed
 
Java_practical_handbook
Manusha Dilan
 
Bang-Bang, you have been hacked - Yonatan Levin, KolGene
DroidConTLV
 
Java PRACTICAL file
RACHIT_GUPTA
 
The Ring programming language version 1.5.1 book - Part 12 of 180
Mahmoud Samir Fayed
 
Final JAVA Practical of BCA SEM-5.
Nishan Barot
 
The Ring programming language version 1.5.4 book - Part 10 of 185
Mahmoud Samir Fayed
 
The Ring programming language version 1.5.3 book - Part 10 of 184
Mahmoud Samir Fayed
 
JavaZone 2014 - goto java;
Martin (高馬丁) Skarsaune
 
2012 JDays Bad Tests Good Tests
Tomek Kaczanowski
 
Java Practical File Diploma
mustkeem khan
 
Advanced Java - Praticals
Fahad Shaikh
 
Java practical(baca sem v)
mehul patel
 

Similar to RxJava и Android. Плюсы, минусы, подводные камни (20)

PDF
Reactive programming on Android
Tomáš Kypta
 
PPTX
Rx workshop
Ryan Riley
 
PDF
Kotlin Developer Starter in Android projects
Bartosz Kosarzycki
 
PDF
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
STX Next
 
PPTX
Binary patching for fun and profit @ JUG.ru, 25.02.2012
Anton Arhipov
 
PDF
Java 8 Lambda Built-in Functional Interfaces
Ganesh Samarthyam
 
PDF
Hw09 Hadoop + Clojure
Cloudera, Inc.
 
ODP
Ast transformations
HamletDRC
 
PPTX
Reactive Programming on Android
Guilherme Branco
 
PDF
Iniciación rx java
Elisa De Gregorio Medrano
 
PDF
"Kotlin и rx в android" Дмитрий Воронин (Avito)
AvitoTech
 
PDF
FP in Java - Project Lambda and beyond
Mario Fusco
 
PDF
Overview of Android Infrastructure
Alexey Buzdin
 
PDF
Overview of Android Infrastructure
C.T.Co
 
PPT
Deuce STM - CMP'09
Guy Korland
 
PDF
Hadoop + Clojure
elliando dias
 
PPTX
Design pattern - part 3
Jieyi Wu
 
PDF
Predictably
ztellman
 
PPTX
Java byte code in practice
Rafael Winterhalter
 
PPTX
2. Design patterns. part #2
Leonid Maslov
 
Reactive programming on Android
Tomáš Kypta
 
Rx workshop
Ryan Riley
 
Kotlin Developer Starter in Android projects
Bartosz Kosarzycki
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
STX Next
 
Binary patching for fun and profit @ JUG.ru, 25.02.2012
Anton Arhipov
 
Java 8 Lambda Built-in Functional Interfaces
Ganesh Samarthyam
 
Hw09 Hadoop + Clojure
Cloudera, Inc.
 
Ast transformations
HamletDRC
 
Reactive Programming on Android
Guilherme Branco
 
Iniciación rx java
Elisa De Gregorio Medrano
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
AvitoTech
 
FP in Java - Project Lambda and beyond
Mario Fusco
 
Overview of Android Infrastructure
Alexey Buzdin
 
Overview of Android Infrastructure
C.T.Co
 
Deuce STM - CMP'09
Guy Korland
 
Hadoop + Clojure
elliando dias
 
Design pattern - part 3
Jieyi Wu
 
Predictably
ztellman
 
Java byte code in practice
Rafael Winterhalter
 
2. Design patterns. part #2
Leonid Maslov
 
Ad

More from Stfalcon Meetups (20)

PDF
Conversion centered design 3
Stfalcon Meetups
 
PDF
Discovery phase
Stfalcon Meetups
 
PPTX
Stfalcon QA Meetup 31.01.2020
Stfalcon Meetups
 
PPTX
Stfalcon QA Meetup 31.01.2020
Stfalcon Meetups
 
PDF
Stfalcon PM Meetup 21.11
Stfalcon Meetups
 
PDF
Stfalcon PM Meetup 21.11
Stfalcon Meetups
 
PDF
Design of the_future_30_05_2019
Stfalcon Meetups
 
PPTX
2 5404811386729530203
Stfalcon Meetups
 
PDF
Team evolution
Stfalcon Meetups
 
PDF
Mobile&Privacy
Stfalcon Meetups
 
PDF
Global sales - a few insights
Stfalcon Meetups
 
PDF
How to build your own startup
Stfalcon Meetups
 
PDF
Первая и последняя встреча с клиентом
Stfalcon Meetups
 
PPTX
Парнерство нидерланды
Stfalcon Meetups
 
ODP
Риси гарного менеджера
Stfalcon Meetups
 
PPTX
Между заказчиком и разработчиком
Stfalcon Meetups
 
PPTX
Cv vs resume
Stfalcon Meetups
 
PPTX
Vue.js
Stfalcon Meetups
 
PPTX
майстер-клас “Управління ризиками”
Stfalcon Meetups
 
PPTX
Kubernetes: від знайомства до використання у CI/CD
Stfalcon Meetups
 
Conversion centered design 3
Stfalcon Meetups
 
Discovery phase
Stfalcon Meetups
 
Stfalcon QA Meetup 31.01.2020
Stfalcon Meetups
 
Stfalcon QA Meetup 31.01.2020
Stfalcon Meetups
 
Stfalcon PM Meetup 21.11
Stfalcon Meetups
 
Stfalcon PM Meetup 21.11
Stfalcon Meetups
 
Design of the_future_30_05_2019
Stfalcon Meetups
 
2 5404811386729530203
Stfalcon Meetups
 
Team evolution
Stfalcon Meetups
 
Mobile&Privacy
Stfalcon Meetups
 
Global sales - a few insights
Stfalcon Meetups
 
How to build your own startup
Stfalcon Meetups
 
Первая и последняя встреча с клиентом
Stfalcon Meetups
 
Парнерство нидерланды
Stfalcon Meetups
 
Риси гарного менеджера
Stfalcon Meetups
 
Между заказчиком и разработчиком
Stfalcon Meetups
 
Cv vs resume
Stfalcon Meetups
 
майстер-клас “Управління ризиками”
Stfalcon Meetups
 
Kubernetes: від знайомства до використання у CI/CD
Stfalcon Meetups
 
Ad

Recently uploaded (20)

PPTX
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
PDF
Letasoft Sound Booster 1.12.0.538 Crack Download+ Product Key [Latest]
HyperPc soft
 
PPT
MergeSortfbsjbjsfk sdfik k
RafishaikIT02044
 
PDF
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
PDF
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
PPTX
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
PDF
Beyond Binaries: Understanding Diversity and Allyship in a Global Workplace -...
Imma Valls Bernaus
 
PPTX
Revolutionizing Code Modernization with AI
KrzysztofKkol1
 
PDF
Alarm in Android-Scheduling Timed Tasks Using AlarmManager in Android.pdf
Nabin Dhakal
 
PDF
Powering GIS with FME and VertiGIS - Peak of Data & AI 2025
Safe Software
 
PDF
Linux Certificate of Completion - LabEx Certificate
VICTOR MAESTRE RAMIREZ
 
PPTX
Migrating Millions of Users with Debezium, Apache Kafka, and an Acyclic Synch...
MD Sayem Ahmed
 
PDF
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
PPTX
Java Native Memory Leaks: The Hidden Villain Behind JVM Performance Issues
Tier1 app
 
PDF
Revenue streams of the Wazirx clone script.pdf
aaronjeffray
 
PDF
Executive Business Intelligence Dashboards
vandeslie24
 
PPTX
An Introduction to ZAP by Checkmarx - Official Version
Simon Bennetts
 
PPTX
Feb 2021 Cohesity first pitch presentation.pptx
enginsayin1
 
PDF
GridView,Recycler view, API, SQLITE& NetworkRequest.pdf
Nabin Dhakal
 
PPTX
Platform for Enterprise Solution - Java EE5
abhishekoza1981
 
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
Letasoft Sound Booster 1.12.0.538 Crack Download+ Product Key [Latest]
HyperPc soft
 
MergeSortfbsjbjsfk sdfik k
RafishaikIT02044
 
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
Beyond Binaries: Understanding Diversity and Allyship in a Global Workplace -...
Imma Valls Bernaus
 
Revolutionizing Code Modernization with AI
KrzysztofKkol1
 
Alarm in Android-Scheduling Timed Tasks Using AlarmManager in Android.pdf
Nabin Dhakal
 
Powering GIS with FME and VertiGIS - Peak of Data & AI 2025
Safe Software
 
Linux Certificate of Completion - LabEx Certificate
VICTOR MAESTRE RAMIREZ
 
Migrating Millions of Users with Debezium, Apache Kafka, and an Acyclic Synch...
MD Sayem Ahmed
 
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
Java Native Memory Leaks: The Hidden Villain Behind JVM Performance Issues
Tier1 app
 
Revenue streams of the Wazirx clone script.pdf
aaronjeffray
 
Executive Business Intelligence Dashboards
vandeslie24
 
An Introduction to ZAP by Checkmarx - Official Version
Simon Bennetts
 
Feb 2021 Cohesity first pitch presentation.pptx
enginsayin1
 
GridView,Recycler view, API, SQLITE& NetworkRequest.pdf
Nabin Dhakal
 
Platform for Enterprise Solution - Java EE5
abhishekoza1981
 

RxJava и Android. Плюсы, минусы, подводные камни

  • 1. , Tips and, Tips and TricksTricks RxJavaRxJava Yaroslav Heriatovych
  • 4. ObservableObservable Observables fill the gap by being the ideal implementation of access to asynchronous sequences of multiple items single items multiple items synchronous T getData() Iterable<T> getData() asynchronous Future<T> getData() Observable<T> getData()
  • 5. PrimitivesPrimitives public interface Observer <T> { void onCompleted(); void onError(java.lang.Throwable throwable); void onNext(T t); } public class Observable <T> { public final static <T> Observable<T> create(OnSubscribe<T> f) public rx.Subscription subscribe(rx.Observer<? super T> observer) // ... } public static interface OnSubscribe<T> extends Action1<Subscriber<? super T>> {} public interface Subscription { public void unsubscribe(); public boolean isUnsubscribed(); } public abstract class Subscriber<T> implements Observer<T>, Subscription {...}
  • 6. Create ObservableCreate Observable Observable<String> o = Observable.from("a", "b", "c"); Observable<String> o = Observable.just("one object"); Observable<String> o = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("Hello"); subscriber.onNext("World"); subscriber.onCompleted(); } });
  • 7. Transform ObservableTransform Observable o.skip(10).take(5) .map(new Func1<String, String>() { @Override public String call(String s) { return s.toUpperCase(); } }) .subscribe(new Action1<String>() { @Override public void call(String s) { Log.d("rx", s) } });
  • 8. SchedulersSchedulers o.skip(10).take(5) .observeOn(Schedulers.computation()) .map(new Func1<String, String>() { @Override public String call(String s) { return s.toUpperCase(); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<String>() { @Override public void call(String s) { Log.d("rx", s) } });
  • 10. LambdaLambda the new old thingthe new old thing
  • 11. Used lambdas before it was coolUsed lambdas before it was cool
  • 12. Observable<Integer> xs = Observable.just(1, 2, 3, 4, 5, 6, 7); xs.filter(new Func1<Integer, Boolean>() { @Override public Boolean call(Integer x) { return x % 2 == 0; } }).map(new Func1<Integer, Integer>() { @Override public Integer call(Integer x) { return x + 10; } }).subscribe(new Action1<Integer>() { @Override public void call(Integer x) { Rx.this.print(x); } }); Anonymous classes hide logic behind the noise More code - more bugs
  • 14. Observable<Integer> xs = Observable.just(1, 2, 3, 4, 5, 6, 7); xs.filter(x -> x % 2 == 0) .map(x -> x + 10) .subscribe(x -> print(x)); Less noise Clear logic Concise
  • 15. RetrolambdaRetrolambda gradle-retrolambdagradle-retrolambda Once more: Java8 for android development Native support in Android Studio Magic
  • 16. One more thingOne more thing It's safer static class MyActivity extends Activity { Handler handler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String str = "uamobile"; handler.postDelayed(new Runnable() { @Override public void run() { Log.d("Rx", str); } }, 10000); } } class MyActivity$1 extends java.lang.Object implements java.lang.Runnable{ final java.lang.String val$str; final MyActivity this$0; MyActivity$1(cMyActivity, java.lang.String); Code: 0: aload_0 1: aload_1 2: putfield 5: aload_0 6: aload_2 7: putfield 10: aload_0 11: invokespecial 14: return public void run(); Code: 0: ldc 2: aload_0 3: getfield 6: invokestatic 9: pop 10: return }
  • 17. One more thingOne more thing It's safer static class MyActivity extends Activity { Handler handler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String str = "uamobile"; handler.postDelayed(() -> Log.d("Rx", str), 10000); } } final class MyActivity$$Lambda$1 extends java.lang.Object implements java.lang.Runnable{ public void run(); Code: 0: aload_0 1: getfield 4: invokestatic 7: return public static java.lang.Runnable lambdaFactory$(java.lang.String); Code: 0: new 3: dup 4: aload_0 5: invokespecial 8: areturn }
  • 18. One abstractionOne abstraction to rule them allto rule them all
  • 19. final View.OnClickListener clickListener = new View.OnClickListener() { @Override public void onClick(View view) { //... } }; new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //... } }; com.squareup.okhttp.Callback okCallback = new com.squareup.okhttp.Callback() { @Override public void onFailure(Request request, IOException e) { //... } @Override public void onResponse(Response response) throws IOException { //... } }; Observable<Void> click Observable<Intent> broadcasts Observable<Response> responses
  • 20. ViewObservable.text(editText) //Observable<OnTextChangeEvent> .map(event -> event.text) //Observable<CharSequence> .filter(cs -> !TextUtils.isEmpty(cs)) //Observable<CharSequence> .map(cs -> cs.toString().toUpperCase()) //Observable<String> .take(5) //Observable<String> .subscribe(str -> handleString(str)); //Subscription editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {} @Override public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {} int count = 5; @Override public void afterTextChanged(Editable editable) { if (!TextUtils.isEmpty(editable)) { String transformed = editable.toString().toUpperCase(); handleString(transformed); count--; if (count == 0) { editText.removeTextChangedListener(this); } } } }); Events as a streamEvents as a stream
  • 22. Abstract over event producerAbstract over event producer Observable<CharSequence> input = ViewObservable.text(editText) .map(event -> event.text); input.filter(cs -> !TextUtils.isEmpty(cs)) .map(cs -> cs.toString().toUpperCase()) .take(5) .subscribe(str -> handleString(str)); Observable<CharSequence> input = AndroidObservable.fromBroadcast(ctx, intentFilter) .map(intent -> intent.getStringExtra("magic_str")); Call call = okHttpClient.newCall(...); Observable<String> input = executeOkCall(call) .map(response -> { try { return response.body().string(); } catch (IOException e) { throw new RuntimeException(e); } }) .flatMap(bodyString -> Observable.from(bodyString.split("n"))) .observeOn(AndroidSchedulers.mainThread());
  • 24. public Observable<String> fromOkCall1(Call call){ return Observable.create(subscriber -> { try { Response response = call.execute(); subscriber.onNext(response.body().string()); subscriber.onCompleted(); } catch (IOException e) { subscriber.onError(e); } }); }
  • 25. public Observable<String> fromOkCall2(Call call){ return Observable.create(subscriber -> { call.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { subscriber.onError(e); } @Override public void onResponse(Response response) throws IOException { try { subscriber.onNext(response.body().string()); subscriber.onCompleted(); } catch (IOException e) { subscriber.onError(e); } } }); }); }
  • 27. Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("Hello"); subscriber.onNext("uamobile"); subscriber.onCompleted(); } }); Simple (cold) ObservableSimple (cold) Observable observable.subscribe(new Action1<String>() { @Override public void call(String s) { handleString(s); } });
  • 28. Observable<String> lastNcRead = mBriefcaseHelper.getBriefcaseObservable() .flatMap(list -> { Observable<Briefcase> briefcaseObservable = Observable.from(list); Observable<String> maxRead = briefcaseObservable .ofType(NotificationReadBriefcase.class) .map(b -> b.attrs.version) .firstOrDefault("0"); Observable<String> maxClear = briefcaseObservable .ofType(NotificationClearBriefcase.class) .map(b -> b.attrs.version) .firstOrDefault("0"); return Observable.zip( maxRead, maxClear, (a, b) -> a.compareTo(b) > 0 ? a : b ); }); Observable<Boolean> hasNotificationsObservable = mDatastore.getNotifications() .switchMap(notifications -> lastNcRead.flatMap(lastNC -> Observable.from(notifications) .takeWhile(n -> n.getId().compareTo(lastNC) > 0) .isEmpty().map(empty -> !empty) ) ).observeOn(AndroidSchedulers.mainThread()); hasNotificationsObservable .subscribe(hasNotifications -> view.setEnabled(hasNotifications)); Do nothing Execute all above
  • 29. Cold and lazyCold and lazy Observable<Integer> cold = Observable.create(subscriber -> { int result = new Random().nextInt(50); subscriber.onNext(result); subscriber.onCompleted(); }); cold.subscribe(n -> print(n)); //13 cold.subscribe(n -> print(n)); //42 =(
  • 30. Hot and sharedHot and shared ConnectableObservable<Integer> cold = Observable.<Integer>create(subscriber -> { int result = new Random().nextInt(50); subscriber.onNext(result); subscriber.onCompleted(); }).publish(); cold.subscribe(n -> print(n)); //40 cold.subscribe(n -> print(n)); //40 cold.connect();
  • 32. interface Response { List<String> getData(); Observable<Response> next(); } public Observable<Response> apiCall(...) {...} public Observable<String> loadAll(Observable<Response> source) { if (source == null) { return Observable.empty(); } else { return source.flatMap(resp -> { List<String> data = resp.getData(); Observable<Response> next = resp.next(); return Observable.concat( Observable.from(data), loadAll(next) ); }); } } Observable<String> all = loadAll(apiCall(...)) .filter(str -> str.contains("#uamobile")) .take(20) .timeout(1, TimeUnit.MINUTES); Tip: Use infinite squencesTip: Use infinite squences
  • 34. Tip: be careful with evaluation timeTip: be careful with evaluation time Observable<MyHeavyData> dataObservable = loadDataFromNetwork() .timeout(10, TimeUnit.SECONDS) .onErrorResumeNext(Observable.just(loadDataFromStorage())); Observable<MyHeavyData> dataObservable = loadDataFromNetwork() .timeout(10, TimeUnit.SECONDS) .onErrorResumeNext(ex -> Observable.just(loadDataFromStorage()));
  • 37. ProactiveProactive Observable<Integer> items = Observable.create(subscriber -> { int i = 0; while (true) { if(subscriber.isUnsubscribed()) return; subscriber.onNext(i++); } }); items.take(10).subscribe(x -> print(x));
  • 38. ReactiveReactive final LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(ctx); Observable<Intent> broadcasts = Observable.create(subscriber -> { final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { subscriber.onNext(intent); } }; final Subscription subscription = Subscriptions.create( () -> localBroadcastManager.unregisterReceiver(broadcastReceiver) ); subscriber.add(subscription); localBroadcastManager.registerReceiver(broadcastReceiver, intentFilter); });
  • 39. OkHttp exampleOkHttp example public Observable<String> fromOkCall3(Call call){ return Observable.create(subscriber -> { subscriber.add(Subscriptions.create(() -> call.cancel())); call.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { subscriber.onError(e); } @Override public void onResponse(Response response) throws IOException { try { subscriber.onNext(response.body().string()); subscriber.onCompleted(); } catch (IOException e) { subscriber.onError(e); } } }); }); }
  • 40. Functional CollectionsFunctional Collections Right here, in your javaRight here, in your java Observables can be used to operate over simple collections
  • 41. Collection as ObservableCollection as Observable Build-in operators No intermediate allocations Functional style
  • 42. How to useHow to use 1. Create Observable from Iterable Observable.from(list) 2. Transform it using build-in operators .filter(...), .map(...), .flatMap(...) 3. Transform to BlockingObservable and get resut .toBlocking.toList().single() .toBlocking.single() .toBlocking.toIterable()
  • 43. class GameSession { String user; int score; } List<Pair<String, Integer>> leaderboard = Observable.from(gameSessions) .filter(session -> session.score != 0) .groupBy(session -> session.user) .flatMap(groupedSessions -> groupedSessions.map(session -> session.score) .reduce(0, (n1, n2) -> n1 + n2) .map(totalScore -> Pair.create(groupedSessions.getKey(), totalScore)) ) .take(10) .toSortedList((pair1, pair2) -> pair2.second.compareTo(pair1.second)) .toBlocking() .single(); Example: LeaderboardExample: Leaderboard
  • 47. LinksLinks https://github.com/ReactiveX/RxJava/wiki Your Mouse is a Database Principles of Reactive Programming Top 7 Tips for RxJava on Android