본문 바로가기

Android

신기술이라고 막 좋아하다가 탈랄지도....(Kotiln, RxJava, MVVM, Databinding 등등) - 2

[출처] http://reactivex.io/

RxJava


ReactiveX 를 Java 언어를 빌려 표현한것. ReactiveX 는 Observable Stream을 가지고 비동기적 프로그래밍을 할수 있는 API.


예시 코드)


1
2
3
4
5
6
7
8
9
10
11
12
13
Observable<String> myObservable = Observable.from(new String[]{"Hello""world!"});
 
myObservable.subscribe(new Action1<String>() {
 
    @Override
 
    public void call(String s) {
 
        System.out.println(s);
 
    }
 
});
cs




처음 이렇게 봤을 때, 코드는 이해했지만, 머릿속에 든 생각은 '그래서 뭐?' 였다.


이걸 왜 써야하는 것이며, 뭐가 깔끔한 것이고, 뭐가 어떻다는 건지....


왜 ReactiveX 를 써야하나? 하고 글을 검색하면, 정말 수 많은 글이 올라 온다. 


근데 사용법만 알려주고 있고 '왜'는 왜 안말해주는 걸까? 아니, '왜'를 엄청 길고 거창하게 표현한다.


나의 '왜' 경우는, 당연히!, 위에서 쓰자고 하니까...




RxJava 를 사용하여 한 프로젝트를 마친후 소감은.. 그러니까... 굳이 이렇게 덕지덕지 할 필요가 있는 건가...싶지만 그래도 편한 건 알겠다.(솔직히 편한가 싶은데, 다들 편하다고 하니.. 그리고 적응중이라 이렇게 느낄 수도 있고)


쓰레드를 따로 돌리는 것도 간단하고, 연쇄로 Operator 를 쓸 수 있고. 그러다가.. 어어 내가 어디까지 뭘 쓴거지...?


글을 여러개 읽어 보고 하지만, 결국 실제로 사용해보기 전까지는 익숙해지지가 않는다.


그리고 지금도 언제는 RxJava 를 써서 하고, 언제는 안 쓰고 할지 감이 안 온다. 


Build pattern 처럼, 연쇄적으로 operator 를 사용하니 코드가 깔끔해지는 것 같으면서도, 


항상 과도하게 이걸 사용하고 있는 건 아닐까 하는 생각이 든다.









자주 사용했던 상황


- 간단한 네트워크 통신 할 때

1
2
3
4
5
6
7
8
9
10
11
12
Single.just(client)
      .subscribeOn(Schedulers.io())
      .timeout(15, TimeUnit.SECONDS)
      .map {
        it.connect("host address")
        it.login("ID","PASSWORD")
        it}
      .subscribe({
        // handling result of request
      },{
        it.printStackTrace()
      })

cs




- 2개 이상의 서로 연관 없는 변수들의 값을 가지고 계산을 해야할 때


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Observables.combineLatest(appVersionObservable(), clientApiObservable()) 
{ current, latest ->
  latestVersion = latest.name.split("_")[1].substring(1// *.*
  hasNewVersionSubject.onNext(hasNewVersion(current.min(), latestVersion))}
  .subscribe({ 
    // Unit type is come
    },{
      it.printStackTrace()
    })
  .addTo(disposable)
 
 
 
Observable.merge(connectedDeviceObservable, connectionStateObservable)
  .flatMapSingle { rxBluetooth.connectAsClient(it, "UUID") }
  .subscribe({ bluetoothSocket ->
    // Someting to do with bluetoothSocket
  }, { 
    it.printStackTrace()
  })
  .addTo(disposable)
cs



위 두 상황이 제일 많이 사용되었다, 사실 압도적으로 두번째가 많이 사용되었다.










자주 사용한 Operator (combineLatest, merge, filter)



combineLatest


 두 개의 Observable 중 하나가 항목을 배출할 때 배출된 마지막 항목과 다른 한 Observable이 배출한 항목을 결합한 후 함수를 적용하여 실행 후 실행된 결과를 배출한다


1. 2개의 Observable 모두가 항목 배출을 끝낸다.(2개중 마지막 1개의 배출을 받을 때 까지 기다림)

1
2
3
observable1 -> data1
 
observable2 -> data2
cs



2. 받은 2개의 데이터를 가공(data1 과 data2 를 가지고 something 을 가공)

1
f(data1,data2) -> something
cs



3. 가공된 데이터를 배출하게되는 Observable 이 됨

1
Observable(something)
cs


4. 이렇게 생성된 Observable 을 가지고 나머지 연산 및 구독을 함

1
2
3
4
5
6
7
Observables.combineLatest(observable1, observable2) { data1, data2 -> f(data1, data2) }
  .subscribe({ something ->
    // Todo someting
    },{
      it.printStackTrace()
    })
  .addTo(disposable)
cs




merge


 여러개의 Observable들(같은 타입을 배출)이 배출하는 항목들을 병합하여 하나의 Observable로 만든다


1. 같은 타입의 데이터를 배출 하는 복수개의 Observable 들

1
2
3
4
5
6
7
observable1 -> data1    // (타입은 T)
 
observable2 -> data2    // (타입은 T)
 
observable3 -> data3    // (타입은 T)
 
observable4 -> data4    // (타입은 T)
cs



2. Observable1,2,3,4 가 발행하는 것을 한개의 Observable 로 발행

1
(observable1, observable2, observable3, observable4) -> observableN
cs

 


3. 이렇게 생성된 Observable 을 가지고 나머지 연산 및 구독

1
2
3
4
5
6
7
Observable.merge(observable1, observable2, observable3, observable4)
  .subscribe({ data ->  // data's type is T
    // Someting to do with data
  }, { 
    it.printStackTrace()
  })
  .addTo(disposable)
cs






filter


테스트 조건을 만족하는 항목들만 배출한다.

1
2
3
4
5
6
7
observable.filter { data -> data.hasToFiltering() } // data will be filtered by the condition(data.hasToFiltering()).
  .subscribe({ data -> // data is filtered
    // Someting to do with data
  }, { 
    it.printStackTrace()
  })
  .addTo(disposable)
cs










참고 사이트


- http://reactivex.io/


- https://github.com/ReactiveX/RxJava