Rx java essentials

28
RxJava Essentials Rx 자자자 자자자 자자자자 자자자자자

Transcript of Rx java essentials

Page 1: Rx java essentials

RxJava EssentialsRx 자바로 배우는

리액티브 프로그래밍

Page 2: Rx java essentials

목차• 1 장 RX: 닷넷에서 Rx 자바까지• 2 장 왜 옵저버블인가 ?• 3 장 헬로 리액티브 월드• 7 장 스케줄러 : 안드로이드 메인 스레드 문제 해결

Page 3: Rx java essentials

1 장 RX:  닷넷에서 Rx 자바까지

• 리액티브 프로그래밍• 마이크로소프트 리액티브 익스텐션• 자바 세계에 상륙 : 넷플릭스 Rx 자바• Rx 자바는 무언이 다른가 ?

Page 4: Rx java essentials

1.1 Rx 자바 핵심 개념

• 서버 성능을 더욱 활용하기 위한 손쉬운 동시성 • 손쉬운 조건부 비동기 실행 • 콜백 지옥을 벗어나기 위한 적절한 방법 • 리액티브 접근법

Page 5: Rx java essentials

1.2 Rx 이전

• 쓰레드의 단점과1) 스레드 간에는 항상 공유 메모리에 대한 타이밍 이슈가 존재2) 여러 스레드간의 완료 이후 통신을 위해 부가적인 메소드 필요3) 스레드 하나의 생성을 위해서는 최소 하나의 클래스를 생성해야 한다4) 스레드를 생성하고 삭제에는 많은 비용이 소모된다 .

• Java의 개선과정• 1) 의 해결을 위해 , 자바 1.5 에 Callable, Future 라는 인터페이스가 도입되었다 .( 참고)• 2) 의 해결을 위해 , 자바 1.7 에는 CompletionService ( 참고)• 3) 의 해결을 위해 ,   자바 1.8 에는 Lambda Expression 이 도입되었다 . ( 참고)• 4) 의 해결을 위해 ,   자바 1.7 에는 ExecutorService,ForkJoinPool 가 도입되었다 . ( 참고)

Page 6: Rx java essentials

1.2 Rx 이전

• CompletableFuture

• 비동기 타스크간의 연결 , 중간에 발생하는 예외처리를 위해 자바 1.8 에 등장• 새로운 개념은 아니고 , 이미 스칼라에서 Futures 와 Promise, 하스켈같은 순수 함수형언어에서 말하는 모나드의에서 그 컨셉을 빌려왔다고 보면 된다 . 남의 좋은 것은 아주 늦게라도 가져오는 것이 자바의 습성인데 , 다른 언어보다 항상 두발정도 늦게 언어 요소를 도입한다 .

Page 7: Rx java essentials

2 장 왜 옵저블인가 ?• 관련 있는 객체 간에 일관성을 유지하는데 발생하는 문제점들을 해결하기 위한 방법• 스몰토크의 MVC

Page 8: Rx java essentials

2 장 왜 옵저블인가 ?• 관련 있는 객체 간에 일관성을 유지하는데 발생하는 문제점들을 해결하기 위한 방법• 옵저버 패턴• 옵저버 패턴은 언제 사용되는가 ? 

Page 9: Rx java essentials

2.1 Rx 자바 옵저버 패턴 툴킷

• 생산• Observable• Subject

• 소비• Observer• Subscriber

Page 10: Rx java essentials

2.2  옵저버블

• 유연하고 사용하기 쉬우며 메소드 체이닝이 가능할 뿐만 아니라 단일 결과 루틴이나 시퀀스에서도 동작할 수 있다 .

• 생명주기 에서 3 개의 이벤트 • onNext(T)• onError(Throwable)• onCompleted()

Page 11: Rx java essentials

2.2  옵저버블

• 옵저버블 종류• 핫

• 아이템이 생성되자마자 발행을 시작한다 .

• 콜드• 아이템을 발행하기 전에 옵저버가 구독할 때까지 대기한다 .

Page 12: Rx java essentials

2.2  옵저버블• Observable.create

Observable.create(new Observable.OnSubscribe<Object>() {@OverridePublic void call(Subscriber<? Super Object> subscriber) {}

}

• Observable.from

• Observable.just

• Observable.empty

• Observable.never

• Observable.throw

Page 13: Rx java essentials

2.3 Subject(= Observavle + Ob-server)• PublishSubject

• BehaviorSubject

• ReplaySubject

• AsyncSubject

Page 14: Rx java essentials

3 장 헬로 리액티브 월드>> refreshTheList>> refreshTheList onNext appInfos : [Ap-pInfo(mLastUpdateTime=1479161246000, mName=API Demos, mIcon=/data/user/0/com.packtpub.apps.rxjava_essentials/files/API Demos), ...]>> refreshTheList onCompleted

private void refreshTheList() { Log.d(TAG, ">> refreshTheList");

getApps() .toSortedList() .subscribe(new Observer<List<AppInfo>>() { @Override public void onCompleted() { Log.d(TAG, ">> refreshTheList onCompleted"); }

@Override public void onError(Throwable e) { Log.d(TAG, ">> refreshTheList onError");

mSwipeRefreshLayout.setRefreshing(false); }

@Override public void onNext(List<AppInfo> appInfos) { Log.d(TAG, ">> refreshTheList onNext appInfos : " + appInfos);

mRecyclerView.setVisibility(View.VISIBLE); mAdapter.addApplications(appInfos); mSwipeRefreshLayout.setRefreshing(false); storeList(appInfos); } }); }

Page 15: Rx java essentials

3.1 from>> loadList>> loadList onNext appInfo : AppInfo(mLastUpdateTime=1479161246000, mName=API Demos, mIcon=/data/user/0/com.-packtpub.apps.rxjava_essentials/files/API Demos)...>> loadList onCompleted

private void loadList(List<AppInfo> apps) { Log.d(TAG, ">> loadList");

mRecyclerView.setVisibility(View.VISIBLE);

Observable.from(apps) .subscribe(new Observer<AppInfo>() { @Override public void onCompleted() { Log.d(TAG, ">> loadList onCompleted"); mSwipeRefreshLayout.setRefreshing(false); }

@Override public void onError(Throwable e) { Log.d(TAG, ">> loadList onError"); mSwipeRefreshLayout.setRefreshing(false); }

@Override public void onNext(AppInfo appInfo) { Log.d(TAG, ">> loadList onNext appInfo : " + appInfo); mAddedApps.add(appInfo); mAdapter.addApplication(mAddedApps.size() - 1, appInfo); } });}

Page 16: Rx java essentials

3.2 just>> loadApps>> loadApps onNext appInfo : AppInfo(mLastUpdateTime=1479161246000, mName=API Demos, mIcon=/data/user/0/com.packtpub.apps.rxjava_essentials/files/API Demos)…(3 개 )>> loadApps onCompleted

private void loadApps(AppInfo appOne, AppInfo appTwo, AppInfo appThree) { Log.d(TAG, ">> loadApps");

mRecyclerView.setVisibility(View.VISIBLE);

Observable<AppInfo> threeOfThem = Observable.just(appOne, appTwo, appThree); threeOfThem.subscribe(new Observer<AppInfo>() { @Override public void onCompleted() { Log.d(TAG, ">> loadApps onCompleted"); mSwipeRefreshLayout.setRefreshing(false); }

@Override public void onError(Throwable e) { Log.d(TAG, ">> loadApps onError"); mSwipeRefreshLayout.setRefreshing(false); }

@Override public void onNext(AppInfo appInfo) { Log.d(TAG, ">> loadApps onNext appInfo : " + appInfo); mAddedApps.add(appInfo); mAdapter.addApplication(mAddedApps.size() - 1, appInfo); } });

Page 17: Rx java essentials

3.3 repeat>> loadApps>> loadApps onNext appInfo : AppInfo(mLastUpdateTime=1479161246000, mName=API Demos, mIcon=/data/user/0/com.-packtpub.apps.rxjava_essentials/files/API Demos)…(9 개 )>> loadApps onCompleted

private void loadApps(AppInfo appOne, AppInfo appTwo, AppInfo appThree) { Log.d(TAG, ">> loadApps");

mRecyclerView.setVisibility(View.VISIBLE);

Observable<AppInfo> threeOfThem = Observable.just(appOne, appTwo, appThree); threeOfThem = threeOfThem.repeat(3);

threeOfThem.subscribe(new Observer<AppInfo>() { @Override public void onCompleted() { Log.d(TAG, ">> loadApps onCompleted"); mSwipeRefreshLayout.setRefreshing(false); }

@Override public void onError(Throwable e) { Log.d(TAG, ">> loadApps onError"); mSwipeRefreshLayout.setRefreshing(false); }

@Override public void onNext(AppInfo appInfo) { Log.d(TAG, ">> loadApps onNext appInfo : " + appInfo); mAddedApps.add(appInfo); mAdapter.addApplication(mAddedApps.size() - 1, appInfo); } });

Page 18: Rx java essentials

3.4 defer?>> refreshTheList >> refreshTheList onNext appInfos : [AppInfo(mLastUpdateTime=1479161246000, mName=API Demos, mIcon=/data/user/0/com.packtpub.apps.rxjava_essentials/files/API Demos), ...] >> refreshTheList onCompleted

private void refreshTheList() { Log.d(TAG, ">> refreshTheList");

Observable<AppInfo> defer = Observable.defer(this::getApps); defer// getApps() .toSortedList() .subscribe(new Observer<List<AppInfo>>() { @Override public void onCompleted() { Log.d(TAG, ">> refreshTheList onCompleted"); }

@Override public void onError(Throwable e) { Log.d(TAG, ">> refreshTheList onError");

mSwipeRefreshLayout.setRefreshing(false); }

@Override public void onNext(List<AppInfo> appInfos) { Log.d(TAG, ">> refreshTheList onNext appInfos : " + appInfos);

mRecyclerView.setVisibility(View.VISIBLE); mAdapter.addApplications(appInfos); mSwipeRefreshLayout.setRefreshing(false); storeList(appInfos); } }); }

Page 19: Rx java essentials

3.5 range>> rangeTest>> rangeTest onNext Integer : 10>> rangeTest onNext Integer : 11>> rangeTest onNext Integer : 12>> rangeTest onCompleted

private void rangeTest() { Log.d(TAG, ">> rangeTest");

Observable.range(10, 3) .subscribe(new Observer<Integer>() { @Override public void onCompleted() { Log.d(TAG, ">> rangeTest onCompleted"); }

@Override public void onError(Throwable e) { Log.d(TAG, ">> rangeTest onError"); }

@Override public void onNext(Integer integer) { Log.d(TAG, ">> rangeTest onNext Integer : " + integer); } });}

Page 20: Rx java essentials

3.6 interval>> intervalTest>> intervalTest onNext Integer : 0…

private void intervalTest() { Log.d(TAG, ">> intervalTest");

Observable.interval(3, TimeUnit.SECONDS) .take(10) .subscribe(new Observer<Long>() { @Override public void onCompleted() { Log.d(TAG, ">> intervalTest onCompleted"); }

@Override public void onError(Throwable e) { Log.d(TAG, ">> intervalTest onError"); }

@Override public void onNext(Long number) { Log.d(TAG, ">> intervalTest onNext Integer : " + number); } });}

Page 21: Rx java essentials

3.7 timer>> timerTest>> timerTest onNext Integer : 0…

private void timerTest() { Log.d(TAG, ">> timerTest");

Observable.timer(3, 3, TimeUnit.SECONDS) .subscribe(new Observer<Long>() { @Override public void onCompleted() { Log.d(TAG, ">> timerTest onCompleted"); }

@Override public void onError(Throwable e) { Log.d(TAG, ">> timerTest onError"); }

@Override public void onNext(Long number) { Log.d(TAG, ">> timerTest onNext Integer : " + number); } });}

Page 22: Rx java essentials

7 장 스케줄러• 스케줄러

• Schedulers.io• Schedulers.computation• Schedulers.immediate• Schedulers.newThread• Schedulers.trampoline

• 논블로킹 I/O 오퍼레이션• SubscribeOn 과 ObserveOn

• 시간이 오래 걸리는 작업 다루기• 네트워크 작업 실행

Page 23: Rx java essentials

7.1 논블로킹 I/O 오퍼레이션public static void storeBitmap(Context context, Bitmap bitmap, String filename) { Schedulers.io().createWorker().schedule(() -> { blockingStoreBitmap(context, bitmap, filename); });}

private static void blockingStoreBitmap(Context context, Bitmap bitmap, String filename) { FileOutputStream fOut = null; try { fOut = context.openFileOutput(filename, Context.MODE_PRIVATE); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); fOut.flush(); fOut.close(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (fOut != null) { fOut.close(); } } catch (IOException e) { e.printStackTrace(); } }}

Page 24: Rx java essentials

7.2 SubscribeOn 과 ObserveOn• subscribeOn

• observeOn

• onBackpressureBuffer

private void loadList() { mRecyclerView.setVisibility(View.VISIBLE);

getApps() .onBackpressureBuffer() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<AppInfo>() { @Override public void onCompleted() { mSwipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show(); }

@Override public void onError(Throwable e) { Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show(); mSwipeRefreshLayout.setRefreshing(false); }

@Override public void onNext(AppInfo appInfo) { mAddedApps.add(appInfo); mAdapter.addApplication(mAddedApps.size() - 1, appInfo); } });}

Page 25: Rx java essentials

7.3 네트워크 작업 실행• PublishSubject

• create• distinct• observeOn• subscribe

• Observable.create• create• subscribeOn• observeOn• subscribe

Page 26: Rx java essentials

7.3 네트워크 작업 실행 (PublishSubject)private boolean downloadFile(String source, String destination) { … try { … mDownloadProgress.onNext(percentage); … mDownloadProgress.onCompleted(); … } catch (Exception e) { mDownloadProgress.onError(e); } finally { try { … mDownloadProgress.onError(e); }

… mDownloadProgress.onCompleted(); … } return result;}

private PublishSubject<Integer> mDownloadProgress = PublishSubject.create();

@OnClick(R.id.button_download)void download() { mButton.setText(getString(R.string.downloading)); mButton.setClickable(false);

mDownloadProgress .distinct() .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Integer>() { @Override public void onCompleted() { App.L.debug("Completed"); }

@Override public void onError(Throwable e) { App.L.error(e.toString()); }

@Override public void onNext(Integer progress) { mArcProgress.setProgress(progress); } });

Page 27: Rx java essentials

7.3 네트워크 작업 실행 (Observable)private Observable<Boolean> obserbableDownload(String source, String destination) { return Observable.create(subscriber -> { try { boolean result = downloadFile(source, destination); if (result) { subscriber.onNext(true); subscriber.onCompleted(); } else { subscriber.onError(new Throwable("Download failed.")); } } catch (Exception e) { subscriber.onError(e); } });}

String destination = "/sdcard/softboy.avi";obserbableDownload("http://archive.blender.org/fileadmin/movies/softboy.avi", destination) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(success -> { resetDownloadButton(); Intent intent = new Intent(android.content.Intent.ACTION_VIEW); File file = new File(destination); intent.setDataAndType(Uri.fromFile(file), "video/avi"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); }, error -> { Toast.makeText(getActivity(), "Something went south", Toast.LENGTH_SHORT).show(); resetDownloadButton(); });

Page 28: Rx java essentials

참고• RxJava Essentials• http://blog.naver.com/2feelus/220714398973