RxJava2 (RxAndroid2) 로 업그레이드 하기
RxJava2(RxAndroid)가 나온지도 시간이 많이 흘렀네요.
RxJava개발진영에서도 2018년 3,4월경부터는 더이상 지원을 하지 않는다고 하니,
이제는 업그레이드를 위한 준비를 해서 테스트 일정까지 생각해보아야 할 때가 되었는데요.
오늘은 RxJava1에서 RxJava2(RxAndroid)로 업그레이드 하면서 알아야 하는 것에 대해서 정리해 보도록 하겠습니다.
혹시 RxJava1에 관해서는 아래 링크를 참조해 주세요ㅋ
1. dependency설정
RxAndroid2를 사용하기 위해서는 dependency부터 변경해야 겠지요.
이미지에서 하이라이트된 두줄을 추가해 주어야 합니다.
참고로 retrofit을 사용하고 있다면, adapter-rxjava2로 adapter도 변경해주어야 합니다.
이제 준비가 되었으니, RxJava2에서 변경되어서 알아야 하는 것들을 하나씩 보도록 하겠습니다.
2. No Null!
Observable에서 null을 넘기게 되는 경우도 있었는데요.
이제는 더이상 null을 보낼 수 없습니다.
RxAndroid2에서는 NullPointerException이 나옵니다.
Obsrvable에서 흘러나오는 데이터를 구독할 때,
만약 null값이면 어떻게 하라는 코드는 이제 사용할 수 없게 된 것이죠.
Networking에서 사용할 때는, 문제가 조금 생길 수 있는데요.
Server가 200 OK를 보냈는데,
Response의 body에는 null값이 왔다면 어떻게 해야 할까요?
Java8의 Optional도 고려 대상이 될 수 있고,
혹은 단순하게 static final 변수를 만들어서 사용하는 방법도 있을 수 있습니다.
null이 나와야 할 부분에 이 변수로 대체해서 Stream을 주고 받을 때 사용하는 것이지요.
문제를 해결하는 방법은 정말 다양합니다.
아래링크에서는 이와 관련된 다양한 논의가 이루어 지고 있으니 참고해 보시면 좋을 것 같습니다.
https://github.com/ReactiveX/RxJava/issues/4644
이 부분과 관련된 코드를 고치고 QA를 할 때 주의를 기울여야 할 것 같습니다.
특히나 네트워크를 타는 경우는 더욱 그러할 것 같구요.
3. Maybe
RxJava2에서는 Maybe가 추가되었는데요.
Maybe를 사용하면, 하나의 아이템이 있거나 혹은 없게 할 수 있습니다.
하지만 주의해야 할 점은 최대 하나의 아이템만 있을 수 있다는 점인데요.
backpressure에는 대응할 수 없습니다.
(대응할 수 없다라고 하기에는, 애초에 하나의 아이템만 받을 수 있으니까요)
이걸로 Null에 대해서 완벽하게 대응할 수 있다는 것은 아니지만,
경우에 따라서는 Null값에 대해 유연하게 대처할 수 있게 해줍니다.
Maybe는 아이템이 있으면 onSuccess,
없으면 onComplete을 호출합니다.
Exception이 필요가 없는 개념인데요.
잘만쓰면 유용할 수 있을 것 같습니다.
4. Observable vs Flowable
이름에서도 Flow하게 한다는 것이므로, BackPressure에 대응하기 위해 만든 느낌이 나는데요.
Observable과 Flowable을 각각 구분해보면 다음과 같습니다.
Observable은 1000개 미만의 아이템들이 흐를 때 사용하구요,
터치이벤트에 대응할 때도 Observable이면 충분합니다.
이런 이벤트 정도에 BackPressure가 생길일은 없을 테니까요.
Flowable은 10,000개 정도이상의 아이템들이 흘러서,
소스에 생성을 제한해야 할 정도가 될 때 사용해야 하는데요.
외부 저장장소에서 파일을 읽어올 때라던가,
네트워킹을 통해서 데이터를 가져올 때가 예가 될 수 있습니다.
이렇게 BackPressure에 대응하기 위해서 Flowable이 있는 것이고,
RxJava2가 필요하게 된 것이지요.
정리해보면, 사실 개인개발자들이 만드는 앱에서,
BackPressure를 감당해야 할 일은
네트워크 쪽을 재외하고는 거의 없을 것 같네요.
5. from() => fromArray(), fromIterable()
Observable.from()으로 사용하던 메소드를 좀 더 구체적으로 구분해서 사용해야 하는데요.
메소드 명에서 볼 수 있듯이, Array에 대해서는 fromArray를,
ArrayList나 List의 경우에는 fromIterable을 사용해주면 됩니다.
6. subscribe
RxJava2에서는 subscribe를 하고 observer를 넣어주어야 하는데요.
Observer에는 아래와 같이 4개의 메소드를 구현해주어야 합니다.
예전에는 onNext, onError, onComplete이 있었는데요.
이들을 사용하는 방법은 달라지지 않았습니다.
추가된 onSubscribe만 알면 되는데,
이것은 다른곳에서 observer를 subscribe를 하게 되었을 때, 어떻게 할지를 구현하는 곳입니다.
Disposable(RxJava1.0의 Subscription)를 받아서 구현할 수 있습니다.
7. Subscription => Disposable
Subscription이름이 Disposable로 변경되었습니다.
리소스 관리에 편리해서 사용했었던(거의 치트키 수준이었지요),
CompositeSubscription도 CompositeDisposable로 변경되었는데요.
CompositeSubscription에서 add메소드를 사용하던 방법이 약간 달라져서
Rxjava2를 적용할 때 신경써주어야 하는 부분입니다.
기존에는, subscribe메소드가, Subscription을 return해주었기 때문에,
이것을 compositeSubscription의 add 메소드를 이용해서 넣어주기만 하면 되었는데요.
이제는 subscribe메소드가 void를 return해 주기 때문에,
subscribeWith라고 하는 메소드를 사용해주어야 합니다.
예전처럼 subscribe에 observer를 그냥 넣어주면 빨간줄이 생기면서 잘못되었다고 나옵니다.
(정말 고칠 코드가 많아지는 순간이네요.)
subscribeWith를 사용하는 것만으로 끝나지 않습니다.
subscribeWith는 observer를 return해주지,
disposable(rxjava1.0에서의 subscription)을 return해주지 않기 때문인데요.
그래서, 아래와 같이 subscribeWIth에 DisposableObserver를 주어야 합니다.
8. first
일단 이름이 바뀌었습니다.
firstElement로 이름이 바뀌었구요.
무엇보다도 중요한 것은,
반환타입이 Maybe<T>라는 것입니다.
RxJava1에서 RxJava2로 업그레이드하는 단계라면,
경우에 따라서 take메소드를 쓰는 편이 더 수월할 수도 있을 것 같네요.
(저의 경우는 처음으로 흘러나오는 아이템을 받아서 zip메소드에 인자로 사용하였었기 때문에,
그냥 take(1)로 대체 하였습니다.)
9. assertResult
RxAndroid에서 테스트 하기에 애매한 경우가 있었는데요.
아래와 같이 test메소드와 assertResult메소드를 사용하면,
쉽게 원하는 값이 잘 나오는지 확인할 수 있습니다.
2값이 맞는지 확인하려 했지만, 3이었기 때문에
아래와 같이 AssertionError을 보내줍니다.
10. limit 이 없어짐
이제 limit대신에 take를 사용해야 합니다.
11. 기존에 있었으나 다시 보게 되는 Operator들
11-1. Single
Observable이나 Flowable처럼 여러 아이템을 흘려보내는 것이 아니라,
하나의 아이템을 onSuccess나 onError로 흘려보낼 수 있는 Observable의 변형이라고 할 수 있습니다.
하나의 아이템만을 보낼 때는 좀 더 명확해 질 수 있을 것 같네요.
사실, RxAndroid1에서도 존재했었는데요.
많이 사용하지는 않았습니다.
11-2. Completable
Completable자체는 RxAndroid1과 거의 비슷하다고 하는데요.
개인적으로는 많이 사용하질 않고 있었네요.
아이템을 받지 않고, onComplete을 호출하거나,
Exception이 나게 되었을 경우,
onError를 호출하게 됩니다.
onNext는 호출하지 않는 거죠.
특정한 값을 받을 필요는 없고,
단순히 Complete되었는지 혹은 Exception이 발생했는지 알아야 할 때,
사용합니다.
위의 Single, Completable 그리고 Maybe를 잘 분리해서 사용한다면,
좀 더 명확하게 코드를 사용할 수 있을 것 같네요.
12. RxJava2로 업그레이드 하기
위에서 RxJava2에서 바뀐 부분들에 대해서 정리해 보았는데요.
개인적으로 어떤 식으로 업그레이드를 할지 정리해 보겠습니다.
가장 먼저, 위에서 변경된 API스펙들을 참조해서,
기존 앱이 구동되서 테스팅 할 수 있도록,
여러가지 이유로 바뀐 API들의 이름을 변경해서 앱이 돌아가도록 합니다.
특히나 리소스관리를 이유로, CompositeSubscrition을 사용한 경우
7번의 예를 참조하여서 CompositeDisposable과 SubscribeWith 그리고,
DisposableObservable을 이용해 수정해 주어야 하지요.
RxJava1=>2로 변경된 스펙은 아래링크에서 좀더 자세히 알 수 있습니다.
https://github.com/ReactiveX/RxJava/wiki/What%27s-different-in-2.0
그다음이, null에 관한 대응입니다.
기존에 null값을 받아서 사용하거나 한 부분이 코드에 있다면 수정해서 대응해줘야 합니다.
특히나 공공API등 서버에게 요청을 하지 못하는 상태인 개인 개발자들의 경우,
그동안 테스트를 많이하면서 null값등에 대한 방어코드등을 작성해왔을텐데요.
테스트할 생각을 하면 은근히 피곤해지실것 같습니다.
위 부분이 다 되었다면,
backpressure에 대응할 수 있는 Flowable등을 적용하는 것이 다음이라고 할 수 있습니다.
추가적으로 test하기에 좋은 assertResult같은 메소드들을 사용하거나,
Singe, Completable, Maybe등을 활용해서,
좀더 명확한 코드를 만들어주는 것을 다음 단계에서 할 수 있을 것 같네요.
마지막 단계까지 간다면 RxJava2에 조금 익숙해져 있지 않을까 싶습니다.
추가적으로, RxAndroid2로 업그레이드 하는 데 있어서 필요한 부분들은,
계속 이 글을 통해 업그레이드 하도록 하겠습니다.