Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

[1B4]안드로이드 동시성_프로그래밍

44,649 views

Published on

DEVIEW 2014 [1B4]안드로이드 동시성_프로그래밍

Published in: Technology
  • Hello dear, My name is mariam nasrin, I know that this email will meet you in a good health and also surprisingly but God has his own way of bringing people together. Nice to Meet you I would appreciate if you can reply me back( mariamnasrin2@gmail.com ) So that i can explain you more about me. thank Yours mariam.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Cocurrent Programming 참고자료
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

[1B4]안드로이드 동시성_프로그래밍

  1. 1. 안드로이드 동시성 프로그래밍 - RxJava를 활용한 Functional Reactive Programming 최정열 / Sivaworks / 라 스칼라 코딩단䯽 email: myeesan@gmail.com䯽 조현태 / Line + / 라 스칼라 코딩단䯽 email: waynejo1024@gmail.com
  2. 2. 오늘의 목표
  3. 3. 오늘의 목표 함수형 프로그래밍에 한 번 관심을 가져보시는 것은 어떨까요?䯽 ! 함수형을 프로그래밍을 익히는 것이 가장 큰 도전…䯽 ! 더 어려운 부분은 절차형과 함수형에서 효율적인 방법을 선택하는 것!䯽 ! 라 스칼라 코딩단: https://groups.google.com/forum/#!forum/scala-korea䯽 ! 샘플 저장소: https://github.com/orgs/FridayCoders/dashboard (업데이트 예정)䯽 !
  4. 4. 안드로이드 동시성 프로그래밍 1. Plain Old Java Concurrent Programming䯽 2. 생명주기와 동시성 프로그래밍䯽 3. Sequencial Tasks & Parellel Tasks䯽 4. 람다 & 함수형 프로그래밍䯽
  5. 5. 동시성 관련䯽 클래스 & 패키지
  6. 6. 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
  7. 7. Concurrent Programming Thread new Thread() { @Override public void run() { URL url = new URL(strUrl); HttpURLConnection urlConnection = ... urlConnection.connect(); iStream = urlConnection.getInputStream(); bitmap = BitmapFactory.decodeStream(iStream); } }.start(); Background
  8. 8. Thread class 메인 쓰레드의 메시지큐로 전달 new Thread() { @Override public void run() { URL url = new URL(strUrl); HttpURLConnection urlConnection = ... urlConnection.connect(); iStream = urlConnection.getInputStream(); bitmap = BitmapFactory.decodeStream(iStream); ! runOnUiThread(new Runnable() { @Override public void run() { imageView.setImageBitmap(bitmap); } } }.start(); UI Thread
  9. 9. Thread class 예외 발생! new Thread() { @Override public void run() { try{ URL url = new URL(strUrl); HttpURLConnection urlConnection = ... urlConnection.connect(); iStream = urlConnection.getInputStream(); bitmap = BitmapFactory.decodeStream(iStream); } catch (Exception e){ log(e.toString); } runOnUiThread(new Runnable() { @Override public void run() { imageView.setImageBitmap(bitmap); } } }.start(); Background
  10. 10. Thread class 예외는 백그라운드에서 발생하지만, 메시지는 UI쓰레드로… new Thread() { @Override public void run() { try{ URL url = new URL(strUrl); HttpURLConnection urlConnection = ... urlConnection.connect(); iStream = urlConnection.getInputStream(); bitmap = BitmapFactory.decodeStream(iStream); } catch (Exception e){ log(e.toString); runOnUiThread(new Runnable(){ showToast(“다운로드가 실패했습니다.”); }); } runOnUiThread(new Runnable() { @Override public void run() { imageView.setImageBitmap(bitmap); } } }.start(); Background UI Thread
  11. 11. Thread class 예외 처리 … ... try{ URL url = new URL(strUrl); HttpURLConnection urlConnection = ... urlConnection.connect(); iStream = urlConnection.getInputStream(); bitmap = BitmapFactory.decodeStream(iStream); } catch (MalformedURLException e){ log.e(e.toString); } catch (IOException e){ runOnUiThread(new Runnable(){ showToast(“다운로드가 실패했습니다.”); }); } catch (Exception e){ // ... } ...
  12. 12. Thread class 리팩토링 Bitmap downloadUrl(String strUrl) { try { iStream = getInputStream(strUrl); } catch (Exception e) { handleException(e, new OnError(){ String onError(){ return “다운로드 실패”; } }); } finally { close(iStream); } return BitmapFactory.decodeStream(iStream); } ! private void handleException(Exception e, OnError onError) { ... } 보기 편하게 람다식으로…
  13. 13. Thread class 구현을 보지 않으면 어떤 쓰레들에서 동작하는지 모르겠다… Bitmap downloadUrl(String strUrl) { try { iStream = getInputStream(strUrl); } catch (Exception e) { handleException(e, ()-> { “다운로드 실패” }); } finally { close(iStream); } return BitmapFactory.decodeStream(iStream); } ! private void handleException(Exception e, OnError onError) { ... } 이 메소드는 백그라운드? 아님, UI Trehad? ! 구현을 들여다 보지 않으면 모르겠는걸?
  14. 14. Thread class 현재 쓰레드에서 메소드 호출과 UI쓰레드 호출을 비교 Bitmap downloadUrl(String strUrl) { ... handleException(e, ()-> “다운로드 실패” ); } ! ! ! // 1 void handleException(Exception e, OnError onError) { runOnUiThread(new Runnable(){ void run(){ log.d(onError.call());} } UI 쓰레드 로깅은 백그라운드에서 처리해도 되는데, UI 쓰레드에서 호출하는건 낭비 닐까? } ! // 2 void handleException(Exception e, OnError onError) { log.d(onError.call()); } 현재 쓰레드 (Background)
  15. 15. Thread class 오류를 뷰에 반영하고 싶은데… Bitmap downloadUrl(String strUrl) { ... handleException(e, ()-> { Toast.makeText(getActivity(), ()-> { textView.setText(“다운로드 실패”) }}); } ! // 1 void handleException(Exception e, OnError onError) { runOnUiThread(new Runnable(){ void run(){ onError.call(); } } } ! // 2 void handleException(Exception e, OnError onError) { onError.call(); } 뷰를 조작하는 코드를 전달 하면?
  16. 16. Thread class CalledFromWrongThreadException Bitmap downloadUrl(String strUrl) { ... handleException(e, ()-> { Toast.makeText(getActivity(), ()-> { textView.setText(“다운로드 실패”) }}); } ! // 1 void handleException(Exception e, OnError onError) { runOnUiThread(new Runnable(){ void run(){ onError.call(); } } } ! // 2 -> CalledFromWrongThreadException void handleException(Exception e, OnError onError) { onError.call(); } UI 쓰레드 외에서는 뷰를 조작 할 수 없음!
  17. 17. Thread class 모든 메소드에 어떤 쓰레드에서 작동하는지 이름을 붙여보자. Bitmap downloadUrl(String strUrl) { ... handleException(e, ()-> { Toast.makeText(getActivity(), ()-> { textView.setText(“다운로드 실패”) }}); } ! // 1 void handleExceptionOnBgThread(Exception e, OnError onError) { runOnUiThread(new Runnable(){ void run(){ onError.call(); } } } ! // 2 void handleExceptionOnUiThread(Exception e, OnError onError) { onError.call(); } 모든 메소드의 이름을 이렇게 짓는 것은 무리야!
  18. 18. Life Cycle 생명주기와 쓰레드
  19. 19. 생명주기와 쓰레드 쓰레드를 시작했으면 독립적으로 존재 UI Thread Activity A onDestroy() Background Thread Activity B Activity A가 종료 되어도 쓰레드는 독립적으로 살아 있음
  20. 20. 생명주기와 쓰레드 Inner class 사용시 메무리 누수 UI Thread Activity A Reference Background Thread 쓰레드가 암묵적으로 참조하고 있어서, onDestroy()가 호출 된 후에도, GC되지 않음! Activity B onDestroy() 성능 저하, 메모리 낭비 Inner class로 쓰레드를 만들면 암북적으로 액티비티를 참조
  21. 21. 생명주기와 쓰레드 쓰레드를 종료 시킬 깔끔한 방법의 필요성 onStop() onDestroy() UI Thread Activity A Background Thread 어디선간 쓰레드를 종료 해야겠네! 어떻게 종료 시키지? interrupt? 또, try ~ catch ~ final?
  22. 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. 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. 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. 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. 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
  27. 27. AsyncTask class 다운로드 + Ui + 예외 처리 (?) @Override protected void onPreExecute() { progressBar.setVisibility(View.VISIBLE); } ! @Override protected Bitmap doInBackground(String... params) { try { bitmap = downloadBitmap(params); } catch (Exception e) {...} return bitmap; } ! @Override protected void onPostExecute(Bitmap bitmap) { imageView.setImageBitmap(bitmap); progressBar.setVisibility(View.GONE); } UI 쓰레드
  28. 28. AsyncTask class 다운로드 + Ui + 예외 처리 (?) @Override protected void onPreExecute() { progressBar.setVisibility(View.VISIBLE); } ! @Override protected Bitmap doInBackground(String... params) { try { bitmap = downloadBitmap(params); } catch (Exception e) {...} return bitmap; } ! @Override protected void onPostExecute(Bitmap bitmap) { imageView.setImageBitmap(bitmap); progressBar.setVisibility(View.GONE); } 백그라운드 쓰레드
  29. 29. AsyncTask class 다운로드 + Ui + 예외 처리 (?) @Override protected void onPreExecute() { progressBar.setVisibility(View.VISIBLE); } ! @Override protected Bitmap doInBackground(String... params) { try { bitmap = downloadBitmap(params); } catch (Exception e) {...} return bitmap; } ! @Override protected void onPostExecute(Bitmap bitmap) { imageView.setImageBitmap(bitmap); progressBar.setVisibility(View.GONE); } 예외는 백그라운드 쓰레드에서 발생하는데, UI Thread로 어떻 게 전달하지?
  30. 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. 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. 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
  33. 33. 동시성 관련䯽 라이브러리
  34. 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. 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. 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. 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. 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. 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. 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. 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
  42. 42. Concurrent Programming Android Event Sources KEY & TOUCH ACCELEROMETER GRAVITY GYROSCOPE LIGHT MAGNETIC ORIENTATION LOCATION PRESSURE
  43. 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. 44. 흔한 로그인 시나리오 1. Auth 2. Token 3. Login 4. Result 5. Request 6. Image Login with 순서대로 실행 되어야 함
  45. 45. Sequencial tasks 순서를 갖는 작업들 UI Thread Req Resp Background TASK A TASK B TASK C
  46. 46. Sequencial tasks 특히, Volley Callback 만을 지원하는 라이브러리 사용시 불필요한 UI 쓰레드 점유 UI Thread Req Resp Background TASK A TASK B TASK C
  47. 47. Sequencial tasks 구현 방식 • Nested Callbacks • Future combination • SingleThreadExecutor • Handler + Looper Callback hell을 해결 할 수 있지만, 소스 네비게이션시 라인 점프는 늘어 날 수 있음. 하나의 쓰레드와 Task를 결합. 단, 오류 처리는 쉽지 않음 직접 워커를 만듦 커스텀 콜백 인터페이스를 정의 해야 함
  48. 48. 흔한 로그인 시나리오 Callback hell requestFacebookLogin(new Callback() { public void onSuccess(Result result) { ... } });
  49. 49. 흔한 로그인 시나리오 Callback hell requestFacebookLogin(new Callback() { public void onSuccess(Result result) { String facebookId = result.getFacebookId(); requestLogin(facebookId, new Callback() { ... }); } });
  50. 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. 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. 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. 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
  54. 54. 흔한 컨텐츠 공유 시나리오
  55. 55. 흔한 컨텐츠 공유 시나리오 1. Req 1. Req 1. Req 1. Req
  56. 56. 흔한 컨텐츠 공유 시나리오 1. Req 2. Resp 1. Req 2. Resp 1. Req 2. Resp 1. Req 2. Resp
  57. 57. Parellel Tasks 동시에 수행 해야 하는 작업들 작업이 끝나는 시간은 모두 다를 수 있음. 모든 작업이 끝났을 때, UI에 반영하고 싶은데… UI Thread Login Data Thread A Data latency Thread B Thread C Data latency Data latency
  58. 58. 흔한 컨텐츠 공유 시나리오 1. Req 2. Resp 1. Req 2. Resp 1. Req 2. Resp 1. Req 2. Resp 작업이 완료䯽 되었습니다.
  59. 59. Parellel Tasks 구현 방식 각각의 태스크를 수행하고 flag를 통해 결과를 취합 • Creating Multiple Threads • CountDownLatch, MultiThreadExecutor (Thread Pool) 요청이 많은 경우 쓰레드 풀을 이용 concurrent 패키지의 CountDownLatch
  60. 60. Composed Tasks 순차 + 병렬 Request Task A Task B Task C Task A Task B Task B Result 앱을 통해 사진과 글을 포스팅 (순차 태스크) 포스팅한 글을 SNS에 공유 (병렬 태스크)
  61. 61. 이런거 없나? 어떤 데이터가 있는데…䯽 어떤 쓰레드에서 수행하고,䯽 필요한 데이터만 걸러내고,䯽 데이터를 어떻게 변환하고,䯽 오류 발생시에는 어떻게 대응할지,䯽 어떤 쓰레드에서 결과를 받을지,䯽 시작하면,䯽 ! 필요한 경우 취소 할 수 있어야 한다.䯽 ! 테스트도 쉬워야겠고!䯽 유추 가능한 것은 생략 할 수 있으면 좋겠다.
  62. 62. 이런거 없나? observable䯽 어떤 쓰레드에서 수행하고,䯽 필요한 데이터만 걸러내고,䯽 데이터를 어떻게 변환하고,䯽 오류 발생시에는 어떻게 대응할지,䯽 어떤 쓰레드에서 결과를 받을지,䯽 시작하면,䯽 ! 필요한 경우 취소 할 수 있어야 한다.䯽 ! 테스트도 쉬워야겠고!䯽 유추 가능한 것은 생략 할 수 있으면 좋겠다.
  63. 63. 이런거 없나? observable䯽 .subscribeOn(background)䯽 필요한 데이터만 걸러내고,䯽 데이터를 어떻게 변환하고,䯽 오류 발생시에는 어떻게 대응할지,䯽 어떤 쓰레드에서 결과를 받을지,䯽 시작하면,䯽 ! 필요한 경우 취소 할 수 있어야 한다.䯽 ! 테스트도 쉬워야겠고!䯽 유추 가능한 것은 생략 할 수 있으면 좋겠다.
  64. 64. 이런거 없나? observable䯽 .subscribeOn(background)䯽 .filter(paidUser())䯽 데이터를 어떻게 변환하고,䯽 오류 발생시에는 어떻게 대응할지,䯽 어떤 쓰레드에서 결과를 받을지,䯽 시작하면,䯽 ! 필요한 경우 취소 할 수 있어야 한다.䯽 ! 테스트도 쉬워야겠고!䯽 유추 가능한 것은 생략 할 수 있으면 좋겠다.
  65. 65. 이런거 없나? observable䯽 .subscribeOn(background)䯽 .filter(paidUser())䯽 .map(stringToJson())䯽 오류 발생시에는 어떻게 대응할지,䯽 어떤 쓰레드에서 결과를 받을지,䯽 시작하면,䯽 ! 필요한 경우 취소 할 수 있어야 한다.䯽 ! 테스트도 쉬워야겠고!䯽 유추 가능한 것은 생략 할 수 있으면 좋겠다.
  66. 66. 이런거 없나? observable䯽 .subscribeOn(background)䯽 .filter(paidUser())䯽 .map(stringToJson())䯽 .doOnError(handleError())䯽 어떤 쓰레드에서 결과를 받을지,䯽 시작하면,䯽 ! 필요한 경우 취소 할 수 있어야 한다.䯽 ! 테스트도 쉬워야겠고!䯽 유추 가능한 것은 생략 할 수 있으면 좋겠다.
  67. 67. 이런거 없나? observable䯽 .subscribeOn(background)䯽 .filter(paidUser())䯽 .map(stringToJson())䯽 .doOnError(handleError())䯽 .observeOn(mainThread)䯽 시작하면,䯽 ! 필요한 경우 취소 할 수 있어야 한다.䯽 ! 테스트도 쉬워야겠고!䯽 유추 가능한 것은 생략 할 수 있으면 좋겠다.
  68. 68. 이런거 없나? observable䯽 .subscribeOn(background)䯽 .filter(paidUser())䯽 .map(stringToJson())䯽 .doOnError(handleError())䯽 .observeOn(mainThread)䯽 .subscribe() -> subscription䯽 ! 필요한 경우 취소 할 수 있어야 한다.䯽 ! 테스트도 쉬워야겠고!䯽 유추 가능한 것은 생략 할 수 있으면 좋겠다.
  69. 69. 이런거 없나? observable䯽 .subscribeOn(background)䯽 .filter(paidUser())䯽 .map(stringToJson())䯽 .doOnError(handleError())䯽 .observeOn(mainThread)䯽 .subscribe() -> subscription䯽 ! subscription.unsubscribe()䯽 ! 테스트도 쉬워야겠고!䯽 유추 가능한 것은 생략 할 수 있으면 좋겠다.
  70. 70. 이런거 없나? observable䯽 .subscribeOn(background)䯽 .filter(paidUser())䯽 .map(stringToJson())䯽 .doOnError(handleError())䯽 .observeOn(mainThread)䯽 .subscribe() -> subscription䯽 ! subscription.unsubscribe()䯽 ! ! assert…(paidUser())䯽 assert…(stringToJson())䯽 assert…(handleError()) ! 유추 가능한 것은 생략 할 수 있으면 좋겠다.
  71. 71. 이런거 없나? observable䯽 .subscribeOn(background)䯽 .filter(paidUser())䯽 .map(stringToJson())䯽 .doOnError(handleError())䯽 .observeOn(mainThread)䯽 .subscribe() -> subscription䯽 ! subscription.unsubscribe()䯽 ! !
  72. 72. RxJava
  73. 73. RxJava 로직에만 집중 테스트 용이성 가독성 이름짓기? 내가 작성하는 코드가 어떤 쓰레드에서 돌아갈지 지금 당장은 관심이 없어. 왜냐하면, 실제 사용 할 시점에서 지정하면 되니까. 모듈화가 쉽다 == 테스트하기 쉽다 메소드 체이닝, 왼쪽에서 오른쪽으로 읽자 코드가 하는 일은 코드 자체가 표현하도록 하자.
  74. 74. Custom Events 3초 동안 입력이 없으면 추천 검색어를 제시
  75. 75. Custom Events D 3초 동안 입력이 없으면 추천 검색어를 제시
  76. 76. Custom Events D E V 3초 동안 입력이 없으면 추천 검색어를 제시
  77. 77. Custom Events 1s D E V 3초 동안 입력이 없으면 추천 검색어를 제시
  78. 78. Custom Events 1s 2s D E V 3초 동안 입력이 없으면 추천 검색어를 제시
  79. 79. Custom Events 1s 2s 3s D E V dev 검색 요청 3초 동안 입력이 없으면 추천 검색어를 제시
  80. 80. Custom Events 1s 2s 3s D E V dev 검색 요청 3초 동안 입력이 없으면 추천 검색어를 제시
  81. 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. 등록 된 태스크가 수행되며 콜백
  82. 82. 람다 안드로이드 스튜디오 사용시 코드 폴딩을 통해 간결하게 표현되는 놈?
  83. 83. 람다 Runnable task = new Runnable(){ @Override public void run(){ System.out.println("Hello Lamba"); } }; Runnable task2 = () -> { System.out.println("Hello Lamba"); };
  84. 84. 람다 인터페이스가 하나의 메소드를 호출하면 굳이 메소드의 이름을 적을 필요는 없으니 생략 Runnable task = new Runnable(){ @Override public void run(){ System.out.println("Hello Lamba"); } }; Runnable task2 = () -> { System.out.println("Hello Lamba"); };
  85. 85. 람다 파라미터는 비었으니 빈 괄호를 넣어주자 Runnable task = new Runnable(){ @Override public void run(){ System.out.println("Hello Lamba"); } }; Runnable task2 = () -> { System.out.println("Hello Lamba"); };
  86. 86. 람다 Runnable task = new Runnable(){ @Override public void run(){ System.out.println("Hello Lamba"); } }; Runnable task2 = () -> { System.out.println("Hello Lamba"); }; 화살표 나오면 람다식! 블럭 내의 내용은 그대로~
  87. 87. 이클립스에서 람다 사용 Xtend Xtend -> 자바 클래스로 변환 • 안드로이드의 Swift Eclipse에서 만들었음에도 리팩토링 기능이 취약함. 프로젝트가 커질수록 컴파일 타임이 급격히 증가 자체적으로 Guava 활용. 테스트 작성시 코드를 • 람다식은 익명 클래스를 통해 구현함 IntelliJ에서는 그냥 텍스트파일 빌드 프로세스를 고민 할 필요가 있음. 극히 간결하게 유지 할 수 있음. 메소드 단위 테스트가 불편 • 자바코드로 컴파일 되므로 호환성 문제가 없음 • 함수형 프로그래밍의 특징을 상당부분 수용함 • Eclipse IDE 지원 단점: 호환성 끝판왕 자바와 스칼라의 중간 어디쯤
  88. 88. 안드로이드 스튜디오에서 람다 사용 RetroLambda 스튜디오의 기본기능인 폴딩도 괜찮지만, 람다 사용이 조금 더 편함 바이트 코드 조작을 통한 람다 사용 • 암묵적 참조로 클래스 참조로 인한 메모리 문제가 없음
  89. 89. 함수형 프로그래밍 외부에서 건드릴 수 없음! 람다식이 함수형 프로그래밍은 절대 아님!
  90. 90. 함수형 프로그래밍의 특징 불 대수 x, y z 는 숫자이거나 집합 (x ∧ z) ∨ (y ∧ z) = (x ∨ y) ∧ z
  91. 91. 함수형 프로그래밍의 특징 불 대수 (x ∧ z) ∨ (y ∧ z) = (x ∨ y) ∧ z 람다 대수 클래스가 함수라면! 람다 대수에 의해 연산 가능! (λx.(λx.x)) y # λx.y
  92. 92. Circle Progress
  93. 93. RxJava Callback => Observable onDraw(Canvas canvas) Observer<Canvas>
  94. 94. RxJava Callback => Observable Subscriber<? super Canvas> canvasSubscriber; ! @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvasSubscriber.onNext(canvas); } RxJava를 통해 콜백을 마치 컬렉션 처럼 바꿔줌
  95. 95. RxJava Callback => Observable 60fps Observable onDraw(Canvas canvas) Observer<Canvas> 이제 collection 처럼 사용가능
  96. 96. RxJava Callback => Observable Observer<Canvas> Observable 함수형 특징을 가진 언어는 다들 비슷비슷 Java 8’s Stream RxJava’s Observable getDataFromLocalMemory() .skip(10) .take(5) .filter(...) .map(s -> s + " mapped" ) .forEach( print(s) ) getDataFromNetwork() .skip(10) .take(5) .filter(...) .map(s -> s + " mapped" ) .subscribe( print(s) )
  97. 97. RxJava Callback => Observable sineValueObservable drawCircle() Zip canvasObservable 지퍼 맞음
  98. 98. RxJava Callback => Observable sineValueObservable drawCircle() Zip canvasObservable 지퍼 맞음
  99. 99. RxJava Callback => Observable sineValueObservable drawCircle() Zip canvasObservable 지퍼 맞음
  100. 100. RxJava Callback => Observable canvasObservable sineValueObservable drawCircle() Zip 두 collection(obsavable)의 각각 요소를 하나씩 결합! 짝이 성사되면 그리기 수행!
  101. 101. RxJava Callback => Observable canvasObservable sineValueObservable drawCircle() Zip 결과물 역시 Obserable 이므로, 추가적인 연산이 얼만든지 가능함~
  102. 102. 왜 RxJava?
  103. 103. 왜 RxJava?
  104. 104. Reactive Extension
  105. 105. ReactiveX RxJs의 형제
  106. 106. 너무 어려워요… 함수형 프로그래밍은 어려운게 아닙니다.䯽 ! 익숙해지는데 시간이 좀 걸릴 뿐입니다.䯽 ! Rx와 함수형이 만능은 아닙니다.䯽 ! 칼퇴근을 보장하진 못하지만,䯽 ! 품질은 높아지고, 스트레스는 낮아집니다.䯽 ! 어렵게 느껴지면, 금요일 라 스칼라 코딩단에 구경오세요䯽 ! 같이 고민해봐요.䯽 ! …안드로이드 개발자 항시 대기 䯽 !
  107. 107. RxJAVA?!
  108. 108. RxJava 1. RxJava란?䯽 ! 2. RxJava(Thread, 이벤트 합성, 시간 관리, Subject, 예외 관리)䯽 ! 3. RxJava With MVVM䯽 !
  109. 109. RxJava란? Excel䯽 - 각 항목에 변화가 있으면 자동으로 감지해서 값을 갱신해준다.䯽 ! ! A B C 1 2 10 20 30 = A1+A2
  110. 110. RxJava란? Excel䯽 - 각 항목에 변화가 있으면 자동으로 감지해서 값을 갱신해준다.䯽 ! ! A B C 1 2 10 30 = A1+A2
  111. 111. RxJava란? Excel䯽 - 각 항목에 변화가 있으면 자동으로 감지해서 값을 갱신해준다.䯽 ! ! A B C 1 2 10 30 = A1+A2 30
  112. 112. RxJava란? Excel䯽 - 각 항목에 변화가 있으면 자동으로 감지해서 값을 갱신해준다.䯽 ! ! A B C 1 2 10 = A1+A2 30
  113. 113. RxJava란? Excel䯽 - 각 항목에 변화가 있으면 자동으로 감지해서 값을 갱신해준다.䯽 ! ! A B C 1 2 10 = A1+A2 30 40
  114. 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. 115. RxJava - Observable, Observer란? Observable - 관측 가능한 값의 흐름를 나타내는 객체 (생산자)䯽 - subscribe 함수를 통해 구독이 가능하며, 구독자에게 값을 흐름을 알려준다.䯽 ! Observer - 값의 흐름를 받는 객체 (소비자)䯽 - Observable의 값의 흐름에 따라 onNext, onError, onCompelete를 호출 받는다.䯽 ! OnNext OnComplete OnError
  116. 116. RxJava - Observable, Observer란? eventSource.subscribe((event)-> { // some action. } ); Observable Observer
  117. 117. RxJava - subscribe/unsubscribe subscribe / unsubcribe䯽 - subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽 unsubscribe를 통해 구독을 해지한다.䯽 ! ! Button Function View Observable! (Operation! or! Producer) Observable! (Operation) Observer
  118. 118. RxJava - subscribe/unsubscribe subscribe / unsubcribe䯽 - subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽 unsubscribe를 통해 구독을 해지한다.䯽 ! ! Button onSubscribe() Function subscribe() View Observable! (Operation! or! Producer) Observable! (Operation) Observer
  119. 119. RxJava - subscribe/unsubscribe subscribe / unsubcribe䯽 - subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽 unsubscribe를 통해 구독을 해지한다.䯽 ! ! Button Function View Observable! (Operation! or! Producer) Observable! (Operation) Observer onSubscribe() subscribe() onNext() onNext()
  120. 120. RxJava - subscribe/unsubscribe subscribe / unsubcribe䯽 - subscribe 를 통하여 Observable의 값의 변화를 구독하고,䯽 unsubscribe를 통해 구독을 해지한다.䯽 ! ! Button Function View Observable! (Operation! or! Producer) Observable! (Operation) Observer onSubscribe() subscribe() onNext() onNext() . . . . . .
  121. 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. 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. 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. 124. RxJava - map 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 TextView에 출력하는 시나리오 EditText Function TextView
  125. 125. RxJava - map 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 TextView에 출력하는 시나리오 EditText Function TextView Text A fun(x) TextA-1
  126. 126. RxJava - map 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 TextView에 출력하는 시나리오 EditText Function TextView Text B fun(x) TextB-1 Text A fun(x) TextA-1
  127. 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. 128. RxJava - map map䯽 - 전달되는 값에 함수를 적용해서 새로운 값을 만들어냄 䯽 ! ! eventSource.map((value) -> {return fun(value);}) .subscribe((result) -> { ! // show result. });
  129. 129. RxJava - flatMap 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오 EditText Async Function TextView
  130. 130. RxJava - flatMap 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오 EditText Async Function TextView Text A
  131. 131. RxJava - flatMap 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오 EditText Async Function TextView Text A fun(x)
  132. 132. RxJava - flatMap 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오 EditText Async Function TextView fun(x) TextA-1 Text A
  133. 133. RxJava - flatMap 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오 EditText Async Function TextView Text A Text B fun(x) TextA-1
  134. 134. RxJava - flatMap 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오 EditText Async Function TextView fun(x) Text B TextA-1 Text A fun(x)
  135. 135. RxJava - flatMap 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오 EditText Async Function TextView fun(x) TextA-1 Text A fun(x) TextB-1 Text B
  136. 136. RxJava - flatMap 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오 EditText Async Function TextView fun(x) Text B Text C TextA-1 Text A fun(x) TextB-1
  137. 137. RxJava - flatMap 키보드 입력값 출력 시나리오䯽 - 키를 입력하면 추천 검색어를 서버에서 받아와 출력하는 시나리오 EditText Async Function TextView fun(x) TextA-1 Text A fun(x) Text C TextB-1 Text B fun(x)
  138. 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. 139. RxJava - flatMap flatmap䯽 - 미래에 0개 ~ n개의 결과를 반환하는 함수를 적용한다.䯽 ! ! eventSource.flatMap((value) -> {return longlongFunc(value);}) .subscribe((Result) -> { ! // show result. ! }); Observable
  140. 140. Thread 관리
  141. 141. RxJava - Scheduler 이미지 다운로드 시나리오䯽 - 버튼을 클릭하면 이미지를 다운받아 표시하는 예제 UI Thread IO Thread UI Thread Click Image Image
  142. 142. RxJava - Scheduler subscribeOn - 비동기 결과값을 가져오는 쓰레드를 결정한다 䯽 observeOn - 결과 값을 처리할 쓰레드를 결정한다. ClickEvents.flatMap((event) -> { return asyncDownloadImage(params) .subscribeOn(Schedulers.io()); }) .observeOn(AndroidSchedulers.mainThread()) .subscribe((image) -> { // show result. });
  143. 143. RxJava - Scheduler observeOn䯽 - 결과 값을 처리할 쓰레드를 결정한다. Event observeOn(MainThreadScheduler) Thread Main Thread
  144. 144. RxJava - Scheduler subscribeOn䯽 - 비동기 결과값을 가져오는 쓰레드를 결정한다. subscribeOn(IOThreadScheduler) IO Thread Event IO Thread
  145. 145. RxJava - Scheduler Schedulers.computation()䯽 - 단순 연산을 처리하는 Thread들의 Pool로 구성된 Scheduler.䯽 ! Schedulers.io()䯽 - IO처리를 담당하는 Thread들의 Pool로 구성된 Scheduler.䯽 - 필요에 따라 자동으로 Pool의 크기를 늘리거나 줄인다.䯽 ! Schedulers.newThread()䯽 - 새로운 쓰레드를 만드는 Scheduler.䯽
  146. 146. RxJava - Scheduler AndroidSchedulers.mainThread( )䯽 - Android의 Main Thread에서 작업을 수행한다.䯽 ! AndroidSchedulers.handlerThread(Handler handler)䯽 - 특정 Thread를 사용하는 Handler이용하는 Scheduler를 생성한다.䯽 ! Schedulers.from(Executor executor)䯽 - 특정 Executor를 사용하는 Scheduler를 생성한다.䯽 ! !
  147. 147. 이벤트 합성
  148. 148. RxJava - combineLatest, merge combineLatest䯽 - Observable 들의 이벤트들 중 가장 최신 이벤트 값을 합성해서 사용한다.䯽 ! Observable.combineLatest(color, shape, new Func2<Color, Shape, Image>() { @Override public Image call(Color color, Shape shape) { return image.createFrom(color, shape); } } );
  149. 149. RxJava - combineLatest, merge combineLatest䯽 - Observable 들의 중 가장 최신의 이벤트 값을 합성한다.䯽 ! Color combineLatest( ) Shape Image
  150. 150. RxJava - combineLatest, merge combineLatest䯽 - Observable 들의 중 가장 최신의 이벤트 값을 합성한다.䯽 ! Color combineLatest( ) 1 Shape Image
  151. 151. RxJava - combineLatest, merge combineLatest䯽 - Observable 들의 중 가장 최신의 이벤트 값을 합성한다.䯽 ! Color combineLatest( ) 1 Shape Image 2 2
  152. 152. RxJava - combineLatest, merge combineLatest䯽 - Observable 들의 중 가장 최신의 이벤트 값을 합성한다.䯽 ! Color combineLatest( ) 1 Shape Image 2 2 3 3
  153. 153. RxJava - combineLatest, merge combineLatest䯽 - Observable 들의 중 가장 최신의 이벤트 값을 합성한다.䯽 ! Color combineLatest( ) 1 Shape Image 2 2 3 4 3 4
  154. 154. RxJava - combineLatest, merge merge䯽 - Observable 들의 이벤트들을 합성해서 사용한다.䯽 ! Observable<Void> clickEvnets = Observable.merge(clickEventFromButtonA, clickEventFromButtonB);
  155. 155. RxJava - combineLatest, merge merge䯽 - Observable 들의 이벤트들을 합성해서 사용한다.䯽 ! Login Button merge( ) Enter Key Login Event
  156. 156. RxJava - combineLatest, merge merge䯽 - Observable 들의 이벤트들을 합성해서 사용한다.䯽 ! Login Button merge( ) Login Event 1 1 Enter Key
  157. 157. RxJava - combineLatest, merge merge䯽 - Observable 들의 이벤트들을 합성해서 사용한다.䯽 ! Login Button merge( ) Login Event 1 1 Enter Key 2 2
  158. 158. RxJava - combineLatest, merge merge䯽 - Observable 들의 이벤트들을 합성해서 사용한다.䯽 ! Login Button merge( ) Login Event 1 1 Enter Key 3 2 2 3
  159. 159. RxJava - combineLatest, merge merge䯽 - Observable 들의 이벤트들을 합성해서 사용한다.䯽 ! Login Button merge( ) Login Event 1 1 Enter Key 3 2 4 2 3 4
  160. 160. 시간 관리
  161. 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. 162. RxJava - Time delay䯽 - 모든 이벤트를 주어진 시간만큼 지연한다.䯽 ! Observer delay( )
  163. 163. RxJava - Time delay䯽 - 모든 이벤트를 주어진 시간만큼 지연한다.䯽 ! 1 Observer delay( )
  164. 164. RxJava - Time delay䯽 - 모든 이벤트를 주어진 시간만큼 지연한다.䯽 ! 1 Observer 1 delay( )
  165. 165. RxJava - Time delay䯽 - 모든 이벤트를 주어진 시간만큼 지연한다.䯽 ! 1 2 Observer 1 delay( )
  166. 166. RxJava - Time delay䯽 - 모든 이벤트를 주어진 시간만큼 지연한다.䯽 ! 1 2 Observer 1 2 delay( )
  167. 167. RxJava - Time delay䯽 - 모든 이벤트를 주어진 시간만큼 지연한다.䯽 ! 1 2 3 Observer 1 2 delay( )
  168. 168. RxJava - Time delay䯽 - 모든 이벤트를 주어진 시간만큼 지연한다.䯽 ! 1 2 3 Observer 1 2 3 delay( )
  169. 169. RxJava - Time throttleFirst䯽 - 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽 ! Observer throttleFirst( )
  170. 170. RxJava - Time throttleFirst䯽 - 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽 ! Observer throttleFirst( ) 1 1
  171. 171. RxJava - Time throttleFirst䯽 - 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽 ! Observer throttleFirst( ) 1 1
  172. 172. RxJava - Time throttleFirst䯽 - 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽 ! Observer throttleFirst( ) 1 2 1
  173. 173. RxJava - Time throttleFirst䯽 - 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽 ! Observer throttleFirst( ) 1 1 2 3 3
  174. 174. RxJava - Time throttleFirst䯽 - 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽 ! Observer throttleFirst( ) 1 1 2 3 3
  175. 175. RxJava - Time throttleFirst䯽 - 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽 ! Observer throttleFirst( ) 1 1 2 3 4 3
  176. 176. RxJava - Time throttleFirst䯽 - 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽 ! Observer 3 5 throttleFirst( ) 1 1 3 5 2 4
  177. 177. RxJava - Time throttleFirst䯽 - 한 이벤트 후의 일정 시간만큼의 이벤트를 무시한다.䯽 ! Observer 3 5 throttleFirst( ) 1 1 3 5 2 4
  178. 178. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer throttleWithTimeout( )
  179. 179. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer throttleWithTimeout( ) 1
  180. 180. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer throttleWithTimeout( ) 1
  181. 181. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer throttleWithTimeout( ) 1 1
  182. 182. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer throttleWithTimeout( ) 1 2 1
  183. 183. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer throttleWithTimeout( ) 1 2 1
  184. 184. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer 1 2 3 throttleWithTimeout( ) 1
  185. 185. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer 1 2 3 throttleWithTimeout( ) 1
  186. 186. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer 1 2 3 4 throttleWithTimeout( ) 1
  187. 187. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer 1 2 3 4 throttleWithTimeout( ) 1
  188. 188. RxJava - Time throttleWithTimeout䯽 - 일정 시간만큼의 이벤트가 없는 경우에 가장 마지막 이벤트를 전달한다.䯽 ! Observer 1 2 3 4 1 4 throttleWithTimeout( )
  189. 189. Subject
  190. 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));
  191. 191. RxJava - Subject(Observable + Observer) BehaviorSubject䯽 ! ! ! BehaviorSubject Observer1 Observer2
  192. 192. RxJava - Subject(Observable + Observer) BehaviorSubject䯽 ! ! 1 ! BehaviorSubject Observer1 Observer2
  193. 193. RxJava - Subject(Observable + Observer) BehaviorSubject䯽 ! ! 1 ! subscribe() BehaviorSubject Observer1 Observer2
  194. 194. RxJava - Subject(Observable + Observer) BehaviorSubject䯽 ! ! 1 ! subscribe() 1 BehaviorSubject Observer1 Observer2
  195. 195. RxJava - Subject(Observable + Observer) BehaviorSubject䯽 ! ! ! 1 2 2 subscribe() 1 BehaviorSubject Observer1 Observer2
  196. 196. RxJava - Subject(Observable + Observer) BehaviorSubject䯽 ! ! ! 1 2 2 subscribe() 1 subscribe() BehaviorSubject Observer1 Observer2
  197. 197. RxJava - Subject(Observable + Observer) BehaviorSubject䯽 ! ! ! 1 2 2 subscribe() 1 2 subscribe() BehaviorSubject Observer1 Observer2
  198. 198. RxJava - Subject(Observable + Observer) BehaviorSubject䯽 ! ! ! 1 2 2 subscribe() 1 2 3 3 3 subscribe() BehaviorSubject Observer1 Observer2
  199. 199. RxJava - Subject(Observable + Observer) PublishSubject䯽 ! ! PublishSubject Observer1 Observer2
  200. 200. RxJava - Subject(Observable + Observer) PublishSubject䯽 ! ! 1 PublishSubject Observer1 Observer2
  201. 201. RxJava - Subject(Observable + Observer) PublishSubject䯽 ! ! 1 subscribe() PublishSubject Observer1 Observer2
  202. 202. RxJava - Subject(Observable + Observer) PublishSubject䯽 ! ! 1 2 2 subscribe() PublishSubject Observer1 Observer2
  203. 203. RxJava - Subject(Observable + Observer) PublishSubject䯽 ! ! 1 2 2 subscribe() subscribe() PublishSubject Observer1 Observer2
  204. 204. RxJava - Subject(Observable + Observer) PublishSubject䯽 ! ! 1 2 subscribe() 3 2 3 3 subscribe() PublishSubject Observer1 Observer2
  205. 205. RxJava - Subject(Observable + Observer) Replay Subject䯽 ! ! ReplaySubject Observer1 Observer2
  206. 206. RxJava - Subject(Observable + Observer) Replay Subject䯽 ! ! 1 ReplaySubject Observer1 Observer2
  207. 207. RxJava - Subject(Observable + Observer) Replay Subject䯽 ! ! 1 subscribe() ReplaySubject Observer1 Observer2
  208. 208. RxJava - Subject(Observable + Observer) Replay Subject䯽 ! ! 1 subscribe() ReplaySubject Observer1 Observer2 1
  209. 209. RxJava - Subject(Observable + Observer) Replay Subject䯽 ! ! 1 2 2 subscribe() ReplaySubject Observer1 Observer2 1
  210. 210. RxJava - Subject(Observable + Observer) Replay Subject䯽 ! ! 1 2 2 subscribe() subscribe() ReplaySubject Observer1 Observer2 1
  211. 211. RxJava - Subject(Observable + Observer) Replay Subject䯽 ! ! 1 2 2 subscribe() subscribe() ReplaySubject Observer1 Observer2 1 1
  212. 212. RxJava - Subject(Observable + Observer) Replay Subject䯽 ! ! 1 2 2 subscribe() subscribe() ReplaySubject Observer1 Observer2 1 1 2
  213. 213. RxJava - Subject(Observable + Observer) Replay Subject䯽 ! ! 1 2 2 subscribe() subscribe() ReplaySubject Observer1 Observer2 1 1 2 3 3 3
  214. 214. 예외 관리
  215. 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. 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. 217. RxJava - Error Handling retry䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! GetDataFromNetwork() .subscribeOn(Schedulers.io()) .retry() Observer retry()
  218. 218. RxJava - Error Handling retry䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! GetDataFromNetwork() .subscribeOn(Schedulers.io()) .retry() Observer retry() 1 1
  219. 219. RxJava - Error Handling retry䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! GetDataFromNetwork() .subscribeOn(Schedulers.io()) .retry() Observer retry() 1 X 1
  220. 220. RxJava - Error Handling retry䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! GetDataFromNetwork() .subscribeOn(Schedulers.io()) .retry() Observer retry() 1 X 1
  221. 221. RxJava - Error Handling retry䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! GetDataFromNetwork() .subscribeOn(Schedulers.io()) .retry() Observer retry() 1 X 1 3 3
  222. 222. RxJava - Error Handling retry(int n)䯽 - 실패한 경우 자동으로 n회 재시도 합니다.䯽 ! GetDataFromNetwork() .subscribeOn(Schedulers.io()) .retry(1) Observer retry(1)
  223. 223. RxJava - Error Handling retry(int n)䯽 - 실패한 경우 자동으로 n회 재시도 합니다.䯽 ! GetDataFromNetwork() .subscribeOn(Schedulers.io()) .retry(1) Observer retry(1) 1 1
  224. 224. RxJava - Error Handling retry(int n)䯽 - 실패한 경우 자동으로 n회 재시도 합니다.䯽 ! GetDataFromNetwork() .subscribeOn(Schedulers.io()) .retry(1) Observer retry(1) 1 X 1
  225. 225. RxJava - Error Handling retry(int n)䯽 - 실패한 경우 자동으로 n회 재시도 합니다.䯽 ! GetDataFromNetwork() .subscribeOn(Schedulers.io()) .retry(1) Observer retry(1) 1 X 1
  226. 226. RxJava - Error Handling retry(int n)䯽 - 실패한 경우 자동으로 n회 재시도 합니다.䯽 ! GetDataFromNetwork() .subscribeOn(Schedulers.io()) .retry(1) Observer retry(1) 1 X 1 2 2
  227. 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. 228. RxJava - Error Handling retryWhen(Observable)䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! Observer retryWhen()
  229. 229. RxJava - Error Handling retryWhen(Observable)䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! Observer retryWhen() 1 1
  230. 230. RxJava - Error Handling retryWhen(Observable)䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! Observer retryWhen() 1 X 1
  231. 231. RxJava - Error Handling retryWhen(Observable)䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! Observer retryWhen() 1 X 1 delay(3, SECODS)
  232. 232. RxJava - Error Handling retryWhen(Observable)䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! Observer retryWhen() 1 X 1 delay(3, SECODS)
  233. 233. RxJava - Error Handling retryWhen(Observable)䯽 - 실패한 경우 자동으로 재시도 합니다.䯽 ! Observer retryWhen() 1 X 1 3 3 delay(3, SECODS)
  234. 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); })
  235. 235. MVVM With RxJava
  236. 236. RxJava - MVVM Loading Indicator 예제䯽 버튼을 클릭하면 다운로드가 완료될 때까지 Loading indicator를 표시한다.䯽 ! ! // 버튼 클릭 이벤트 Observable<Void> btnClickEvent = … ! Observable.merge( btnClickEvent.map((event) -> {return true;}, btnClickEvent.flatMap((event)-> { return downloadFunction().subscribeOn(Schedulers.io()) }).map((event) -> {return false;}) .observeOn(AndroidSchedulers.main()) ! .subscribe((isVisible) -> { v.setVisibility(isVisible ? View.VISIBLE : View.GONE); )}
  237. 237. RxJava - MVVM Loading Indicator 예제䯽 버튼을 클릭하면 다운로드가 완료될 때까지 Loading indicator를 표시한다.䯽 ! ! // 버튼 클릭 이벤트 Observable<Void> btnClickEvent = … ! Observable.merge( btnClickEvent.map((event) -> {return true;}, btnClickEvent.flatMap((event)-> { return downloadFunction().subscribeOn(Schedulers.io()) }).map((event) -> {return false;}) .observeOn(AndroidSchedulers.main()) ! .subscribe((isVisible) -> { v.setVisibility(isVisible ? View.VISIBLE : View.GONE); )} View Model View
  238. 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. 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. 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 테스트 불 가능 코드 테스트 가능 코드 연결 코드
  241. 241. 결론
  242. 242. 왜 Reactive Programming 인가? 프로그램의 일관성을 유지하는 통일된 방식이 필요䯽 - Event, Thread, 시간, Exception을 처리하기에는 Callback은 조합이 어렵다.䯽 - 그러므로 개개인이 각각의 방식으로 조합하여 복잡성이 증대된다.䯽 ! ! 단순 객체지향으로는 큰 프로그램을 만들기 어렵다.䯽 - 객체지향은 내부의 상세한 구현을 숨긴다.䯽 - 이로인해 잘 만들지 않으면 기대와 다른 동작들로 인해 복잡도가 증가한다.䯽 - 이를 해결하기 위해 객체가 객체를 감싸고 또다시 감싸는 등의 문제가 발생한다.䯽 ! !
  243. 243. 왜 Reactive Programming 인가? 프로그램의 일관성을 유지하는 통일된 방식이 필요䯽 - Event, Thread, 시간, Exception을 처리하기에는 Callback은 조합이 어렵다.䯽 - 그러므로 개개인이 각각의 방식으로 조합하여 복잡성이 증대된다.䯽 ! ! 단순 객체지향으로는 큰 프로그램을 만들기 어렵다.䯽 - 객체지향은 내부의 상세한 구현을 숨긴다.䯽 - 이로인해 잘 만들지 않으면 기대와 다른 동작들로 인해 복잡도가 증가한다.䯽 - 이를 해결하기 위해 객체가 객체를 감싸고 또다시 감싸는 등의 문제가 발생한다.䯽 ! ! 통일된 방식으로 Event, Thread, Time, Exception을 처리할 수 있는 방법 제공
  244. 244. 왜 Reactive Programming 인가? 프로그램의 일관성을 유지하는 통일된 방식이 필요䯽 - Event, Thread, 시간, Exception을 처리하기에는 Callback은 조합이 어렵다.䯽 - 그러므로 개개인이 각각의 방식으로 조합하여 복잡성이 증대된다.䯽 ! ! 단순 객체지향으로는 큰 프로그램을 만들기 어렵다.䯽 - 객체지향은 내부의 상세한 구현을 숨긴다.䯽 - 이로인해 잘 만들지 않으면 기대와 다른 동작들로 인해 복잡도가 증가한다.䯽 - 이를 해결하기 위해 객체가 객체를 감싸고 또다시 감싸는 등의 문제가 발생한다.䯽 ! ! 통일된 방식으로 Event, Thread, Time, Exception을 처리할 수 있는 방법 제공 외부에 제공할 수 있는 읽기 전용의 Observable을 제공하며 내용을 감추지 않아도 됨
  245. 245. 왜 Reactive Programming 인가? 보다 테스트하기 쉬운 구조가 필요하다.䯽 - 일반적인 구현에서는 가장 내부 깊은 곳에 View, Activity 등이 존재한다.䯽 - 이로 인해 테스트에서 View를 제거하지 못해 테스트가 힘들어진다.䯽
  246. 246. 왜 Reactive Programming 인가? 보다 테스트하기 쉬운 구조가 필요하다.䯽 - 일반적인 구현에서는 가장 내부 깊은 곳에 View, Activity 등이 존재한다.䯽 - 이로 인해 테스트에서 View를 제거하지 못해 테스트가 힘들어진다.䯽 MVVM의 구조를 활용하여 OS 종속적인 부분을 최대한 배제하고 테스트할 수 있음
  247. 247. 감사합니다.

×