1. 안드로이드 동시성 프로그래밍 -
RxJava를 활용한 Functional
Reactive Programming
최정열 / Sivaworks / 라 스칼라 코딩단䯽
email: myeesan@gmail.com䯽
조현태 / Line + / 라 스칼라 코딩단䯽
email: waynejo1024@gmail.com
3. 오늘의 목표
함수형 프로그래밍에 한 번 관심을 가져보시는 것은 어떨까요?䯽
!
함수형을 프로그래밍을 익히는 것이 가장 큰 도전…䯽
!
더 어려운 부분은 절차형과 함수형에서 효율적인 방법을 선택하는 것!䯽
!
라 스칼라 코딩단: https://groups.google.com/forum/#!forum/scala-korea䯽
!
샘플 저장소: https://github.com/orgs/FridayCoders/dashboard (업데이트 예정)䯽
!
19. 생명주기와 쓰레드
쓰레드를 시작했으면 독립적으로 존재
UI Thread Activity A
onDestroy()
Background Thread
Activity B
Activity A가 종료 되어도 쓰레드는 독립적으로 살아 있음
20. 생명주기와 쓰레드
Inner class 사용시 메무리 누수
UI Thread
Activity A
Reference
Background Thread
쓰레드가 암묵적으로 참조하고
있어서, onDestroy()가 호출 된
후에도, GC되지 않음!
Activity B
onDestroy()
성능 저하, 메모리 낭비
Inner class로 쓰레드를 만들면 암북적으로 액티비티를 참조
21. 생명주기와 쓰레드
쓰레드를 종료 시킬 깔끔한 방법의 필요성
onStop() onDestroy()
UI Thread Activity A
Background Thread
어디선간 쓰레드를 종료 해야겠네!
어떻게 종료 시키지?
interrupt?
또, try ~ catch ~ final?
22. 생명주기와 쓰레드
Callback 을 사용한 Thread class
MyThread extends Thread{
interface MyCallback {
void onFinishDownloadImage(T t);
}
!
MyCallback callback;
!
@Override public void run() {
// download image...
runOnUiThread(new Runnable() {
@Override public void run() {
callback.onFinishDownloadImage(bitmap);
}
}
};
모든 blocking 작업이 끝나면 콜백을
통해 결과를 전달~
23. 생명주기와 쓰레드
예외 발생
MyThread extends Thread{
interface MyCallback {
void onFinishDownloadImage(T t);
void onError(Exception e);
}
!
MyCallback callback;
!
@Override public void run() {
try {
// download image…
} catch {
callback.onError(e);
}
runOnUiThread(new Runnable() {
@Override public void run() {
callback.onFinishDownloadImage(bitmap);
}
}
};
예외 발생시 유저에게 알려야 하는데,
UI요소에는 직접 처리 할 수 없으므로
콜백 메소드를 추가.
24. Concurrent Programming
Android Concurrent Programming
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
Executor + Thread pool + Future …
Thread 보다 추상화된 제어가 가능!
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
25. Concurrent Programming
Android Concurrent Programming
Thread
concurrent package
Handler
AsyncTask
Service
안드로이드의 UI Thread를 관리하는 놈.
Looper와 함께 사용하고, Looper는 메시지
큐를 가지고 있어서 순차 실행을 보장!
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
26. Concurrent Programming
Android Concurrent Programming
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
Handler + 탬플릿 메소드 패턴
AndroidAnnotations
Guava
greenrobot/EventBus
otto
30. Concurrent Programming
Android Concurrent Programming
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
액티비티의 생명 주기로 부터
영향을 받지 않음!
31. Concurrent Programming
Android Concurrent Programming
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
커서관리 방법 없고,
greenrobot/EventBus
AsyncTask와 문제점 공유
otto
32. Concurrent Programming
Android Concurrent Programming
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
허니컴 이후 등장. compat을 이용해서 이전에도
사용이 가능하며 생명주기 변경시 스스로 처리함
단, ContentProvider 외에는 사용이 어려움
greenrobot/EventBus
otto
34. Concurrent Programming
Third Party Libraries
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
네트워크, 이미지
Callback 기반
35. Concurrent Programming
Third Party Libraries
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
동기, 비동기 (async) 지원
RxJava의 Observable 지원
36. Concurrent Programming
Third Party Libraries
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
37. Concurrent Programming
Third Party Libraries
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
Future
38. Concurrent Programming
Third Party Libraries
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
@Background 어노테이션
내부적으로 ScheduledThreadPool을 활용
39. Concurrent Programming
Third Party Libraries
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
ListenableFuture
40. Concurrent Programming
Third Party Libraries
Thread
concurrent package
Handler
AsyncTask
Service
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
이벤트 버스
RxJava로 대체 할 수 있음
41. Concurrent Programming
Third Party Libraries
Thread
애플리케이션의 설계가 라이브러리 인터페이스에 의존적이 되는 것을 주의!
저마다 Http client, 이미지 캐싱, ThreadPool 관리 서로 다른 정책과 인터페이
concurrent package
Handler
AsyncTask
Service
스를 가지고 있으므로, 중복 설정 및 불필요한 추상화를 주의!
AsyncQueryHandler
Loader
Volley
OkHttp, Retrofit, Picasso
AndroidUniversalImageLoader
AndroidAsync(Http), ION
AndroidAnnotations
Guava
greenrobot/EventBus
otto
43. Parallel tasks䯽
Concurrently executing tasks
멀티 태스크
Sequencial tasks䯽
One after another
Request
Task A
Task B
Task C
Request
반드시 순서대로 실행 되어
야 하는 태스크 묶음
Task A Task B Task C
Result Result
44. 흔한 로그인 시나리오
1. Auth
2. Token
3. Login
4. Result
5. Request
6. Image
Login with
순서대로 실행 되어야 함
46. Sequencial tasks
특히, Volley
Callback 만을 지원하는 라이브러리 사용시
불필요한 UI 쓰레드 점유
UI Thread Req Resp
Background TASK A TASK B TASK C
47. Sequencial tasks
구현 방식
• Nested Callbacks
• Future combination
• SingleThreadExecutor
• Handler + Looper
Callback hell을 해결 할 수 있지만,
소스 네비게이션시 라인 점프는 늘어 날 수 있음.
하나의 쓰레드와 Task를 결합. 단, 오류 처리는 쉽지 않음
직접 워커를 만듦 커스텀 콜백 인터페이스를 정의 해야 함
48. 흔한 로그인 시나리오
Callback hell
requestFacebookLogin(new Callback() {
public void onSuccess(Result result) {
...
}
});
49. 흔한 로그인 시나리오
Callback hell
requestFacebookLogin(new Callback() {
public void onSuccess(Result result) {
String facebookId = result.getFacebookId();
requestLogin(facebookId, new Callback() {
...
});
}
});
50. 흔한 로그인 시나리오
Callback hell
requestFacebookLogin(new Callback() {
public void onSuccess(Result result) {
String facebookId = result.getFacebookId();
requestLogin(facebookId, new Callback() {
public void onSuccess(Result result) {
result.getUserDetails(new Callback() {
@Override public void onSuccess(User user) {
...
}
});
}
});
}
});
예외 처리 추가시 분기문 추가시 depth가 2배씩 증가;;
51. 흔한 로그인 시나리오
재시도 전략
requestFacebookLogin(new Callback() {
public void onSuccess(Result result) {
String facebookId = result.getFacebookId();
requestLogin(facebookId, new Callback() {
public void onSuccess(Result result) {
result.getUserDetails(new Callback() {
@Override public void onSuccess(User user) {
...
}
});
}
public void onFail(Result result){
retry( ??? );
}
});
}
});
각각 Task에 예외가 발생한 작업을 재시도 하고 싶을 땐?
@#!%
52. 흔한 로그인 시나리오
페이스북 로그인 > 앱 서버 로그인 > 초기 데이터 요청 > 오류 처리
requestFacebookLogin(new Callback() {
public void onSuccess(Result result) {
String facebookId = result.getFacebookId();
requestLogin(facebookId, new Callback() {
public void onSuccess(Result result) {
result.getUserDetails(new Callback() {
@Override public void onSuccess(User user) {
...
}
});
}
public void onFail(Result result){
retry( ??? );
showToast(context, R.String.loginFail);
}
});
}
});
UI Thread를 통해 유저에게 알리고 싶은데,
“나는 누구 여긴 어디?”
53. Parallel tasks䯽
Concurrently executing tasks
멀티 태스크
Sequencial tasks䯽
One after another
태스크간의 의존성이 없어, 동시
에 실행 될 수 있음.
그러나, 우리는 UI 프로그래머
Request
Task A
Task B
Task C
Request
Task A Task B Task C
Result Result
56. 흔한 컨텐츠 공유 시나리오
1. Req
2. Resp
1. Req
2. Resp
1. Req
2. Resp
1. Req
2. Resp
57. Parellel Tasks
동시에 수행 해야 하는 작업들
작업이 끝나는 시간은 모두 다를 수 있음.
모든 작업이 끝났을 때, UI에 반영하고 싶은데…
UI Thread Login Data
Thread A Data
latency
Thread B
Thread C
Data latency
Data latency
58. 흔한 컨텐츠 공유 시나리오
1. Req
2. Resp
1. Req
2. Resp
1. Req
2. Resp
1. Req
2. Resp
작업이 완료䯽
되었습니다.
59. Parellel Tasks
구현 방식
각각의 태스크를 수행하고 flag를 통해 결과를 취합
• Creating Multiple Threads
• CountDownLatch, MultiThreadExecutor (Thread Pool)
요청이 많은 경우 쓰레드 풀을 이용
concurrent 패키지의 CountDownLatch
60. Composed Tasks
순차 + 병렬
Request
Task A
Task B
Task C
Task A Task B Task B
Result
앱을 통해 사진과 글을 포스팅
(순차 태스크)
포스팅한 글을 SNS에 공유
(병렬 태스크)
61. 이런거 없나?
어떤 데이터가 있는데…䯽
어떤 쓰레드에서 수행하고,䯽
필요한 데이터만 걸러내고,䯽
데이터를 어떻게 변환하고,䯽
오류 발생시에는 어떻게 대응할지,䯽
어떤 쓰레드에서 결과를 받을지,䯽
시작하면,䯽
!
필요한 경우 취소 할 수 있어야 한다.䯽
!
테스트도 쉬워야겠고!䯽
유추 가능한 것은 생략 할 수 있으면 좋겠다.
62. 이런거 없나?
observable䯽
어떤 쓰레드에서 수행하고,䯽
필요한 데이터만 걸러내고,䯽
데이터를 어떻게 변환하고,䯽
오류 발생시에는 어떻게 대응할지,䯽
어떤 쓰레드에서 결과를 받을지,䯽
시작하면,䯽
!
필요한 경우 취소 할 수 있어야 한다.䯽
!
테스트도 쉬워야겠고!䯽
유추 가능한 것은 생략 할 수 있으면 좋겠다.
63. 이런거 없나?
observable䯽
.subscribeOn(background)䯽
필요한 데이터만 걸러내고,䯽
데이터를 어떻게 변환하고,䯽
오류 발생시에는 어떻게 대응할지,䯽
어떤 쓰레드에서 결과를 받을지,䯽
시작하면,䯽
!
필요한 경우 취소 할 수 있어야 한다.䯽
!
테스트도 쉬워야겠고!䯽
유추 가능한 것은 생략 할 수 있으면 좋겠다.
64. 이런거 없나?
observable䯽
.subscribeOn(background)䯽
.filter(paidUser())䯽
데이터를 어떻게 변환하고,䯽
오류 발생시에는 어떻게 대응할지,䯽
어떤 쓰레드에서 결과를 받을지,䯽
시작하면,䯽
!
필요한 경우 취소 할 수 있어야 한다.䯽
!
테스트도 쉬워야겠고!䯽
유추 가능한 것은 생략 할 수 있으면 좋겠다.
65. 이런거 없나?
observable䯽
.subscribeOn(background)䯽
.filter(paidUser())䯽
.map(stringToJson())䯽
오류 발생시에는 어떻게 대응할지,䯽
어떤 쓰레드에서 결과를 받을지,䯽
시작하면,䯽
!
필요한 경우 취소 할 수 있어야 한다.䯽
!
테스트도 쉬워야겠고!䯽
유추 가능한 것은 생략 할 수 있으면 좋겠다.
66. 이런거 없나?
observable䯽
.subscribeOn(background)䯽
.filter(paidUser())䯽
.map(stringToJson())䯽
.doOnError(handleError())䯽
어떤 쓰레드에서 결과를 받을지,䯽
시작하면,䯽
!
필요한 경우 취소 할 수 있어야 한다.䯽
!
테스트도 쉬워야겠고!䯽
유추 가능한 것은 생략 할 수 있으면 좋겠다.
67. 이런거 없나?
observable䯽
.subscribeOn(background)䯽
.filter(paidUser())䯽
.map(stringToJson())䯽
.doOnError(handleError())䯽
.observeOn(mainThread)䯽
시작하면,䯽
!
필요한 경우 취소 할 수 있어야 한다.䯽
!
테스트도 쉬워야겠고!䯽
유추 가능한 것은 생략 할 수 있으면 좋겠다.
68. 이런거 없나?
observable䯽
.subscribeOn(background)䯽
.filter(paidUser())䯽
.map(stringToJson())䯽
.doOnError(handleError())䯽
.observeOn(mainThread)䯽
.subscribe() -> subscription䯽
!
필요한 경우 취소 할 수 있어야 한다.䯽
!
테스트도 쉬워야겠고!䯽
유추 가능한 것은 생략 할 수 있으면 좋겠다.
69. 이런거 없나?
observable䯽
.subscribeOn(background)䯽
.filter(paidUser())䯽
.map(stringToJson())䯽
.doOnError(handleError())䯽
.observeOn(mainThread)䯽
.subscribe() -> subscription䯽
!
subscription.unsubscribe()䯽
!
테스트도 쉬워야겠고!䯽
유추 가능한 것은 생략 할 수 있으면 좋겠다.
70. 이런거 없나?
observable䯽
.subscribeOn(background)䯽
.filter(paidUser())䯽
.map(stringToJson())䯽
.doOnError(handleError())䯽
.observeOn(mainThread)䯽
.subscribe() -> subscription䯽
!
subscription.unsubscribe()䯽
!
!
assert…(paidUser())䯽
assert…(stringToJson())䯽
assert…(handleError())
!
유추 가능한 것은 생략 할 수 있으면 좋겠다.
73. RxJava
로직에만 집중
테스트 용이성
가독성
이름짓기?
내가 작성하는 코드가 어떤 쓰레드에서 돌아갈지
지금 당장은 관심이 없어.
왜냐하면, 실제 사용 할 시점에서 지정하면 되니까.
모듈화가 쉽다 == 테스트하기 쉽다
메소드 체이닝, 왼쪽에서 오른쪽으로 읽자
코드가 하는 일은 코드 자체가 표현하도록 하자.
81. Custom Events
Custom Events
lastInputTime 0 0 0 3
D E V
1s 2s 3s
Thread
Callback
1. 쓰레드 만들고
2. 이벤트 발생 시간 기록
3. 마지막 이벤트와 현재 시간 비교
4. 설정 값 이상의 차이가 발생시 콜백
또는,
1. 수행할 태스크를 작성
2. 태스크 등록(postDelayed 사용)
3. 이벤트 발생시 등록 이벤트 취소
4. 등록 된 태스크가 수행되며 콜백
84. 람다
인터페이스가 하나의 메소드를 호출하면
굳이 메소드의 이름을 적을 필요는 없으니 생략
Runnable task = new Runnable(){
@Override
public void run(){
System.out.println("Hello Lamba");
}
};
Runnable task2 = () -> { System.out.println("Hello Lamba"); };
85. 람다
파라미터는 비었으니 빈 괄호를 넣어주자
Runnable task = new Runnable(){
@Override
public void run(){
System.out.println("Hello Lamba");
}
};
Runnable task2 = () -> { System.out.println("Hello Lamba"); };
86. 람다
Runnable task = new Runnable(){
@Override
public void run(){
System.out.println("Hello Lamba");
}
};
Runnable task2 = () -> { System.out.println("Hello Lamba"); };
화살표 나오면 람다식!
블럭 내의 내용은 그대로~
87. 이클립스에서 람다 사용
Xtend
Xtend -> 자바 클래스로 변환
• 안드로이드의 Swift
Eclipse에서 만들었음에도 리팩토링 기능이 취약함.
프로젝트가 커질수록 컴파일 타임이 급격히 증가
자체적으로 Guava 활용. 테스트 작성시 코드를
• 람다식은 익명 클래스를 통해 구현함
IntelliJ에서는 그냥 텍스트파일
빌드 프로세스를 고민 할 필요가 있음.
극히 간결하게 유지 할 수 있음.
메소드 단위 테스트가 불편
• 자바코드로 컴파일 되므로 호환성 문제가 없음
• 함수형 프로그래밍의 특징을 상당부분 수용함
• Eclipse IDE 지원
단점:
호환성 끝판왕
자바와 스칼라의 중간 어디쯤
88. 안드로이드 스튜디오에서 람다 사용
RetroLambda
스튜디오의 기본기능인 폴딩도 괜찮지만,
람다 사용이 조금 더 편함
바이트 코드 조작을 통한 람다 사용
• 암묵적 참조로 클래스 참조로 인한 메모리 문제가 없음
108. RxJava
1. RxJava란?䯽
!
2. RxJava(Thread, 이벤트 합성, 시간 관리, Subject, 예외 관리)䯽
!
3. RxJava With MVVM䯽
!
109. RxJava란?
Excel䯽
- 각 항목에 변화가 있으면 자동으로 감지해서 값을 갱신해준다.䯽
!
!
A
B
C
1 2
10 20
30 = A1+A2
110. RxJava란?
Excel䯽
- 각 항목에 변화가 있으면 자동으로 감지해서 값을 갱신해준다.䯽
!
!
A
B
C
1 2
10
30 = A1+A2
111. RxJava란?
Excel䯽
- 각 항목에 변화가 있으면 자동으로 감지해서 값을 갱신해준다.䯽
!
!
A
B
C
1 2
10
30 = A1+A2
30
112. RxJava란?
Excel䯽
- 각 항목에 변화가 있으면 자동으로 감지해서 값을 갱신해준다.䯽
!
!
A
B
C
1 2
10
= A1+A2
30
113. RxJava란?
Excel䯽
- 각 항목에 변화가 있으면 자동으로 감지해서 값을 갱신해준다.䯽
!
!
A
B
C
1 2
10
= A1+A2
30
40
114. RxJava - Observable, Observer란?
Observable - 관측 가능한 값의 흐름를 나타내는 객체 (생산자)䯽
Observer - 값의 흐름를 받는 객체 (소비자)䯽
!
Observable Observer
Button
Click String
Network
Byte[]
Keyboard
Text View
Alert
Image View
Input Text
Error
Image
String
Visibility
Image
Event
115. RxJava - Observable, Observer란?
Observable - 관측 가능한 값의 흐름를 나타내는 객체 (생산자)䯽
- subscribe 함수를 통해 구독이 가능하며, 구독자에게 값을 흐름을 알려준다.䯽
!
Observer - 값의 흐름를 받는 객체 (소비자)䯽
- Observable의 값의 흐름에 따라 onNext, onError, onCompelete를 호출 받는다.䯽
!
OnNext OnComplete
OnError
117. RxJava - subscribe/unsubscribe
subscribe / unsubcribe䯽
- subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽
unsubscribe를 통해 구독을 해지한다.䯽
!
!
Button Function View
Observable!
(Operation!
or!
Producer)
Observable!
(Operation)
Observer
118. RxJava - subscribe/unsubscribe
subscribe / unsubcribe䯽
- subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽
unsubscribe를 통해 구독을 해지한다.䯽
!
!
Button onSubscribe() Function subscribe() View
Observable!
(Operation!
or!
Producer)
Observable!
(Operation)
Observer
119. RxJava - subscribe/unsubscribe
subscribe / unsubcribe䯽
- subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽
unsubscribe를 통해 구독을 해지한다.䯽
!
!
Button Function View
Observable!
(Operation!
or!
Producer)
Observable!
(Operation)
Observer
onSubscribe() subscribe()
onNext() onNext()
120. RxJava - subscribe/unsubscribe
subscribe / unsubcribe䯽
- subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽
unsubscribe를 통해 구독을 해지한다.䯽
!
!
Button Function View
Observable!
(Operation!
or!
Producer)
Observable!
(Operation)
Observer
onSubscribe() subscribe()
onNext() onNext()
.
.
.
.
.
.
121. RxJava - subscribe/unsubscribe
subscribe / unsubcribe䯽
- subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽
unsubscribe를 통해 구독을 해지한다.䯽
!
!
Button Function View
Observable!
(Operation!
or!
Producer)
Observable!
(Operation)
Observer
onSubscribe() subscribe()
onNext() onNext()
.
.
.
.
.
.
onNext() onNext()
122. RxJava - subscribe/unsubscribe
subscribe / unsubcribe䯽
- subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽
unsubscribe를 통해 구독을 해지한다.䯽
!
!
Button Function View
Observable!
(Operation!
or!
Producer)
Observable!
(Operation)
Observer
onSubscribe() subscribe()
onNext() onNext()
.
.
.
.
.
.
onNext() onNext()
onComplete() onComplete()
123. RxJava - subscribe/unsubscribe
subscribe / unsubcribe䯽
- subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽
unsubscribe를 통해 구독을 해지한다.䯽
!
!
Button Function View
Observable!
(Operation!
or!
Producer)
Observable!
(Operation)
Observer
onSubscribe() subscribe()
onNext() onNext()
.
.
.
.
.
.
onNext() onNext()
onComplete() onComplete()
unsubscribe() unsubscribe()
124. RxJava - map
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 TextView에 출력하는 시나리오
EditText
Function
TextView
125. RxJava - map
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 TextView에 출력하는 시나리오
EditText
Function
TextView
Text A
fun(x)
TextA-1
126. RxJava - map
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 TextView에 출력하는 시나리오
EditText
Function
TextView
Text B
fun(x)
TextB-1
Text A
fun(x)
TextA-1
127. RxJava - map
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 TextView에 출력하는 시나리오
EditText
Function
TextView
Text B
fun(x)
TextB-1
Text C
fun(x)
TextC-1
Text A
fun(x)
TextA-1
128. RxJava - map
map䯽
- 전달되는 값에 함수를 적용해서 새로운 값을 만들어냄 䯽
!
!
eventSource.map((value) -> {return fun(value);})
.subscribe((result) -> {
!
// show result.
});
129. RxJava - flatMap
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오
EditText
Async Function
TextView
130. RxJava - flatMap
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오
EditText
Async Function
TextView
Text A
131. RxJava - flatMap
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오
EditText
Async Function
TextView
Text A
fun(x)
132. RxJava - flatMap
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오
EditText
Async Function
TextView
fun(x)
TextA-1
Text A
133. RxJava - flatMap
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오
EditText
Async Function
TextView
Text A Text B
fun(x)
TextA-1
134. RxJava - flatMap
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오
EditText
Async Function
TextView
fun(x)
Text B
TextA-1
Text A
fun(x)
135. RxJava - flatMap
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오
EditText
Async Function
TextView
fun(x)
TextA-1
Text A
fun(x)
TextB-1
Text B
136. RxJava - flatMap
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오
EditText
Async Function
TextView
fun(x)
Text B Text C
TextA-1
Text A
fun(x)
TextB-1
137. RxJava - flatMap
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오
EditText
Async Function
TextView
fun(x)
TextA-1
Text A
fun(x)
Text C
TextB-1
Text B
fun(x)
138. RxJava - flatMap
키보드 입력값 출력 시나리오䯽
- 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오
EditText
Async Function
TextView
fun(x)
TextA-1
Text A
fun(x)
TextB-1
Text B
fun(x)
TextC-1
Text C
139. RxJava - flatMap
flatmap䯽
- 미래에 0개 ~ n개의 결과를 반환하는 함수를 적용한다.䯽
!
!
eventSource.flatMap((value) -> {return longlongFunc(value);})
.subscribe((Result) -> {
!
// show result.
!
});
Observable
145. RxJava - Scheduler
Schedulers.computation()䯽
- 단순 연산을 처리하는 Thread들의 Pool로 구성된 Scheduler.䯽
!
Schedulers.io()䯽
- IO처리를 담당하는 Thread들의 Pool로 구성된 Scheduler.䯽
- 필요에 따라 자동으로 Pool의 크기를 늘리거나 줄인다.䯽
!
Schedulers.newThread()䯽
- 새로운 쓰레드를 만드는 Scheduler.䯽
146. RxJava - Scheduler
AndroidSchedulers.mainThread( )䯽
- Android의 Main Thread에서 작업을 수행한다.䯽
!
AndroidSchedulers.handlerThread(Handler handler)䯽
- 특정 Thread를 사용하는 Handler이용하는 Scheduler를 생성한다.䯽
!
Schedulers.from(Executor executor)䯽
- 특정 Executor를 사용하는 Scheduler를 생성한다.䯽
!
!
161. RxJava - Time
예제) throttleWithTimeout䯽
- 자동 완성 기능䯽
!
// 기본 변수 설정
final PublishSubject<String> inputText = PublishSubject.create();
TextView autoCompleteTextView =
(TextView) findViewById(R.id.auto_complete_text);
!
// 1초동안 사용자 입력이 없는 경우 네트워크에서 값을 받아와서 갱신
inputText.throttleWithTimeout(1, TimeUnit.SECONDS)
.observeOn(Schedulers.io())
.flatMap(new GetAutocompleteKeywordsFromNetwork())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SetTextAction(autoCompleteTextView));
162. RxJava - Time
delay䯽
- 모든 이벤트를 주어진 시간만큼 지연한다.䯽
!
Observer
delay( )
163. RxJava - Time
delay䯽
- 모든 이벤트를 주어진 시간만큼 지연한다.䯽
!
1
Observer
delay( )
164. RxJava - Time
delay䯽
- 모든 이벤트를 주어진 시간만큼 지연한다.䯽
!
1
Observer
1
delay( )
165. RxJava - Time
delay䯽
- 모든 이벤트를 주어진 시간만큼 지연한다.䯽
!
1 2
Observer
1
delay( )
166. RxJava - Time
delay䯽
- 모든 이벤트를 주어진 시간만큼 지연한다.䯽
!
1 2
Observer
1 2
delay( )
167. RxJava - Time
delay䯽
- 모든 이벤트를 주어진 시간만큼 지연한다.䯽
!
1 2 3
Observer
1 2
delay( )
168. RxJava - Time
delay䯽
- 모든 이벤트를 주어진 시간만큼 지연한다.䯽
!
1 2 3
Observer
1 2 3
delay( )
169. RxJava - Time
throttleFirst䯽
- 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽
!
Observer
throttleFirst( )
170. RxJava - Time
throttleFirst䯽
- 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽
!
Observer
throttleFirst( )
1
1
171. RxJava - Time
throttleFirst䯽
- 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽
!
Observer
throttleFirst( )
1
1
172. RxJava - Time
throttleFirst䯽
- 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽
!
Observer
throttleFirst( )
1 2
1
173. RxJava - Time
throttleFirst䯽
- 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽
!
Observer
throttleFirst( )
1
1
2 3
3
174. RxJava - Time
throttleFirst䯽
- 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽
!
Observer
throttleFirst( )
1
1
2 3
3
175. RxJava - Time
throttleFirst䯽
- 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽
!
Observer
throttleFirst( )
1
1
2 3 4
3
176. RxJava - Time
throttleFirst䯽
- 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽
!
Observer
3 5
throttleFirst( )
1
1
3
5
2 4
177. RxJava - Time
throttleFirst䯽
- 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽
!
Observer
3 5
throttleFirst( )
1
1
3
5
2 4
178. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
throttleWithTimeout( )
179. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
throttleWithTimeout( )
1
180. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
throttleWithTimeout( )
1
181. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
throttleWithTimeout( )
1
1
182. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
throttleWithTimeout( )
1 2
1
183. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
throttleWithTimeout( )
1 2
1
184. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
1 2 3
throttleWithTimeout( )
1
185. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
1 2 3
throttleWithTimeout( )
1
186. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
1 2 3 4
throttleWithTimeout( )
1
187. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
1 2 3 4
throttleWithTimeout( )
1
188. RxJava - Time
throttleWithTimeout䯽
- 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽
!
Observer
1 2 3 4
1 4
throttleWithTimeout( )
190. RxJava - Subject(Observable + Observer)
BehaviorSubject를 사용한 SharedPreferences 예제䯽
!
final String KEY = “key_user_id”;
!
// User ID 변수 선언
BehaviorSubject<String> userId = BehaviorSubject.create();
// SharePreference 에서 Background Thread로 값을 읽어온다.
readFromSharedPreferences(KEY, "").subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(userId);
// userId 값이 변경되면 SharePreference에 비동기로 값을 기록한다.
userId.distinctUntilChanged()
.observeOn(Schedulers.io())
.subscribe(new WriteToSharedPreferences(KEY));
215. RxJava - Error Handling
doOnError䯽
- 실패한 경우, 예외를 처리하는 기능을 수행할 수 있습니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError((e) -> {showError(e);})
.subscribe((img) -> {showImage(img);})
1
Observer
1 X
216. RxJava - Error Handling
doOnError䯽
- 실패한 경우, 예외를 처리하는 기능을 수행할 수 있습니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError((e) -> {showError(e);})
.subscribe((img) -> {showImage(img);})
1
Observer
1 X
Error Handling
217. RxJava - Error Handling
retry䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry()
Observer
retry()
218. RxJava - Error Handling
retry䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry()
Observer
retry()
1
1
219. RxJava - Error Handling
retry䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry()
Observer
retry()
1 X
1
220. RxJava - Error Handling
retry䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry()
Observer
retry()
1 X
1
221. RxJava - Error Handling
retry䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry()
Observer
retry()
1 X
1
3
3
222. RxJava - Error Handling
retry(int n)䯽
- 실패한 경우 자동으로 n회 재시도 합니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry(1)
Observer
retry(1)
223. RxJava - Error Handling
retry(int n)䯽
- 실패한 경우 자동으로 n회 재시도 합니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry(1)
Observer
retry(1)
1
1
224. RxJava - Error Handling
retry(int n)䯽
- 실패한 경우 자동으로 n회 재시도 합니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry(1)
Observer
retry(1)
1 X
1
225. RxJava - Error Handling
retry(int n)䯽
- 실패한 경우 자동으로 n회 재시도 합니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry(1)
Observer
retry(1)
1 X
1
226. RxJava - Error Handling
retry(int n)䯽
- 실패한 경우 자동으로 n회 재시도 합니다.䯽
!
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry(1)
Observer
retry(1)
1 X
1
2
2
227. RxJava - Error Handling
retry(int n)䯽
- 실패한 경우 자동으로 n회 재시도 합니다.䯽
!
2 X
GetDataFromNetwork()
.subscribeOn(Schedulers.io())
.retry(1)
Observer
retry(1)
1 X
1
2
X
228. RxJava - Error Handling
retryWhen(Observable)䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
Observer
retryWhen()
229. RxJava - Error Handling
retryWhen(Observable)䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
Observer
retryWhen()
1
1
230. RxJava - Error Handling
retryWhen(Observable)䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
Observer
retryWhen()
1 X
1
231. RxJava - Error Handling
retryWhen(Observable)䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
Observer
retryWhen()
1 X
1
delay(3, SECODS)
232. RxJava - Error Handling
retryWhen(Observable)䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
Observer
retryWhen()
1 X
1
delay(3, SECODS)
233. RxJava - Error Handling
retryWhen(Observable)䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
Observer
retryWhen()
1 X
1
3
3
delay(3, SECODS)
234. RxJava - Error Handling
retryWhen(Observable)䯽
- 실패한 경우 자동으로 재시도 합니다.䯽
!
Observer
retryWhen()
!
GetDataFromNetwork()
1 X
1
3
3
.subscribeOn(Schedulers.io())
.retryWhen((observable) ->
delay(3, SECODS)
{
// 3초마다 재시도
return observable.delay(3, TimeUnit.SECONDS);
})
238. RxJava - MVVM
Model View
User Info
String String
Login Info
String
Profile Image
Text View
Alert
Image View
Input Text
Error
Image
Image
Visibility
Image
Event
View Model
운영체제에䯽
의존적
운영체제에䯽
독립적
239. RxJava - MVVM
Model View
User Info
String String
Login Info
String
Profile Image
Text View
Alert
Image View
Input Text
Error
Image
Image
Visibility
Image
Event
View Model
재사용이䯽
어려움
재사용이
원활함
240. RxJava - MVVM
Model View
User Info
String String
Login Info
String
Profile Image
Text View
Alert
Image View
Input Text
Error
Image
Image
Visibility
Image
Event
View Model
테스트 불
가능 코드
테스트 가능 코드
연결 코드
242. 왜 Reactive Programming 인가?
프로그램의 일관성을 유지하는 통일된 방식이 필요䯽
- Event, Thread, 시간, Exception을 처리하기에는 Callback은 조합이 어렵다.䯽
- 그러므로 개개인이 각각의 방식으로 조합하여 복잡성이 증대된다.䯽
!
!
단순 객체지향으로는 큰 프로그램을 만들기 어렵다.䯽
- 객체지향은 내부의 상세한 구현을 숨긴다.䯽
- 이로인해 잘 만들지 않으면 기대와 다른 동작들로 인해 복잡도가 증가한다.䯽
- 이를 해결하기 위해 객체가 객체를 감싸고 또다시 감싸는 등의 문제가 발생한다.䯽
!
!
243. 왜 Reactive Programming 인가?
프로그램의 일관성을 유지하는 통일된 방식이 필요䯽
- Event, Thread, 시간, Exception을 처리하기에는 Callback은 조합이 어렵다.䯽
- 그러므로 개개인이 각각의 방식으로 조합하여 복잡성이 증대된다.䯽
!
!
단순 객체지향으로는 큰 프로그램을 만들기 어렵다.䯽
- 객체지향은 내부의 상세한 구현을 숨긴다.䯽
- 이로인해 잘 만들지 않으면 기대와 다른 동작들로 인해 복잡도가 증가한다.䯽
- 이를 해결하기 위해 객체가 객체를 감싸고 또다시 감싸는 등의 문제가 발생한다.䯽
!
!
통일된 방식으로 Event, Thread, Time, Exception을 처리할 수 있는 방법 제공
244. 왜 Reactive Programming 인가?
프로그램의 일관성을 유지하는 통일된 방식이 필요䯽
- Event, Thread, 시간, Exception을 처리하기에는 Callback은 조합이 어렵다.䯽
- 그러므로 개개인이 각각의 방식으로 조합하여 복잡성이 증대된다.䯽
!
!
단순 객체지향으로는 큰 프로그램을 만들기 어렵다.䯽
- 객체지향은 내부의 상세한 구현을 숨긴다.䯽
- 이로인해 잘 만들지 않으면 기대와 다른 동작들로 인해 복잡도가 증가한다.䯽
- 이를 해결하기 위해 객체가 객체를 감싸고 또다시 감싸는 등의 문제가 발생한다.䯽
!
!
통일된 방식으로 Event, Thread, Time, Exception을 처리할 수 있는 방법 제공
외부에 제공할 수 있는 읽기 전용의 Observable을 제공하며 내용을 감추지
않아도 됨
245. 왜 Reactive Programming 인가?
보다 테스트하기 쉬운 구조가 필요하다.䯽
- 일반적인 구현에서는 가장 내부 깊은 곳에 View, Activity 등이 존재한다.䯽
- 이로 인해 테스트에서 View를 제거하지 못해 테스트가 힘들어진다.䯽
246. 왜 Reactive Programming 인가?
보다 테스트하기 쉬운 구조가 필요하다.䯽
- 일반적인 구현에서는 가장 내부 깊은 곳에 View, Activity 등이 존재한다.䯽
- 이로 인해 테스트에서 View를 제거하지 못해 테스트가 힘들어진다.䯽
MVVM의 구조를 활용하여 OS 종속적인 부분을 최대한 배제하고 테스트할 수 있음