RxAndroid로 리액티브 앱 만들기 #2

  1. RxAndroid로 리액티브 앱 만들기 #1
  2. RxAndroid로 리액티브 앱 만들기 #2
  3. RxAndroid로 리액티브 앱 만들기 #3
  4. RxAndroid로 리액티브 앱 만들기 #4

이 시리즈는 마이크로소프트웨어에 기고된 내용이 일부 수정되어 포함되어 있습니다.


이번에는 지난 시간에 이어 데이터를 어떻게 다루는지 Map을 비롯한 오퍼레이터를 통해 살펴보겠습니다. 또 복잡한 콜백 클래스와 메서드를 람다를 통해 어떻게 코드를 단순화 시키는지를 다루겠습니다.

데이터 가공 Map

map은 한 데이터를 다른 데이터로 바꾸는 오퍼레이터입니다. 원본의 데이터는 변경하지 않고 새로운 스트림을 만들어 냅니다. 스트림의 데이터를 각각 10 씩 곱을 하는 예를 볼 수 있습니다.

이렇게 map 사용하려면 인자 하나를 받아 값을 10배를 곱해 반환하는 메서드를 map 전달해야 합니다.

.map(new Func1<Integer, Integer>() {
    @Override
    public Integer call(Integer value) {
        return value * 10;
    }
})

RxAndroid를 사용하여 앱을 개발할 때 미리 준비된 다양한 RxJava 오퍼레이터를 사용할 수 있습니다. 오퍼레이터는 기존에 작성된 메서드를 재사용하여 전체 값을 변경할 수 있는 도구입니다. 값을 재사용 가능한 함수를 이용해서 가공한다는 부분에서 함수형 프로그래밍과 일맥상통하는 부분이 있습니다.

이런 개발 뉴스를 더 만나보세요

문자열을 대문자로 바꾸는 것도 쉽게 구현할 수 있습니다.

simpleObservable
    .map(new Func1<String, String>() {
        @Override
        public String call(String text) {
            return text.toUpperCase();
        }
    })
    .subscribe(new Action1<String>() {
        @Override
        public void call(String text) {
            ((TextView) findViewById(R.id.textView)).setText(text);
        }
    });

옵저버블의 스트림을 대문자로 변환하는 (사실은 새로운 스트림을 만드는) map 호출하고 그것을 서브스크라이버에 연결하는 것을 보여줍니다.

map 이용할 때는 같은 타입으로만 변경해야 할 수 있는 것은 아닙니다. 다른 타입으로도 바꿀 수 있습니다.

simpleObservable
    .map(new Func1<String, Integer>() {
        @Override
        public Integer call(String text) {
            return text.length();
        }
    })
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer length) {
            ((TextView) findViewById(R.id.textView)).setText("length: " + length);
        }
    });

단일 데이터, 컬렉션을 옵저버블 생성을 위한 유틸리티

simpleObservable은 문자열 하나만 전달하는 간단한 옵저버블인데 이런 경우 항상 새로 옵저버블을 만들 필요는 없습니다. 옵저버블을 쉽게 만들 수 있게 도와주는 유틸리티 메서드가 있습니다.

Observable<String> simpleObservable = Observable.just("Hello RxAndroid");

연속적인 데이터를 처리하기 위한 유틸리티 Observable.from도 있습니다. 이 유틸리티를 이용하면 배열이나 컬렉션을 보다 간편하게 처리합니다.

번잡한 문법을 람다로 간단히

기존의 자바 문법에서 RxAndroid (RxJava) 프로그래밍을 할 때 로직과 상관없는 요소들이 많이 발견됩니다. 어노테이션, 클래스 선언, 메서드 선언 등의 요소들이 코드에서 반복되지요. 어떤 부분들은 반복을 제거할 수 없지만 Rx를 사용하기 위해 반복적으로 생성되는 클래스와 메서드 선언은 람다를 통해 줄일 수 있습니다. 람다를 사용하면 코드가 간결해져 가독성이 높아집니다.

Observable<String> simpleObservable = Observable.just("Hello Lambda!!");
simpleObservable
    .map(text -> text.length())
    .subscribe(
        length -> ((TextView) findViewById(R.id.textView)).setText("length: " + length));

자바 코드가 매우 간결해진 것을 볼 수 있습니다. 람다 문법이 생소한 독자를 위해 코드 단위로 비교하며 설명하겠습니다.

.map(new Func1<String, Integer>() {
    @Override
    public Integer call(String text) {
        return text.length();
    }
})

람다를 사용하기 전 map 코드입니다. 람다는 단일 메서드를 가지고 있는 경우만 적용할 수 있습니다. 여기에서 메서드 인자 부분 이전의 번잡한 내용을 지워봅시다.

.map((String text) -> {
    return text.length();
})

익명 객체 부분을 제거한 람다 map 코드입니다. 인자의 타입을 추론할 수 있다면 그 부분도 생략할 수 있습니다.

.map((text) -> {
    return text.length();
})

인자가 하나인 경우에는 괄호를 생략할 수 있습니다.

.map(text -> text.length())

람다 블록 내에 문장이 하나이고 리턴값을 가진다면 블록, 세미콜론, 리턴 키워드를 지울 수 있습니다.

람다의 단 한가지 단점은 자바 8이상에서만 쓸 수 있다는 점입니다. 안드로이드는 자바 8을 지원하지 못하며 람다를 쓰기 위해서는 이전 버전에서 람다를 쓸 수 있게 하는 포팅 라이브러리를 사용해야 합니다.

람다 포팅 중 안드로이드에 알맞는 라이브러리는 레트로람다(Retrolambda)입니다. 레트로람다 라이브러리는 속도 상의 약점이 없고 기술 선도 기업들이 2013년 부터 안드로이드에 테스트해서 어느정도 검증 받았다고 볼 수 있습니다.

레트로람다 라이브러리를 사용하기 위해서는 그래들 코드의 설정의 수정이 필요합니다.

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.3.0-beta3'
    }
}

apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "io.realm.simpleobservable"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'io.reactivex:rxandroid:1.1.0'
}

상단에 레트로람다 관련 빌드스크립트가 추가된 것과 apply plugin: 'com.android.application' 뒤에 apply plugin: 'me.tatarka.retrolambda'가 추가된 것을 주목하세요.

만약 자바 8과 옛 버전을 함께 쓰길 원한다면 Gradle Retrolambda Plugin 프로젝트를 참고하세요.

이번 글에서는 리액티브 프로그래밍의 가장 기초적인 오퍼레이터와 그 활용법을 배웠습니다. 그 개념을 바탕으로 데이터 스트림을 간단히 연결하고 변형을 할 수 있습니다.

다음 시간에는 다양한 옵저버블과 오퍼레이터 등을 합성하여 사용자 인터페이스와 상호작용하는 방법을 알아보며 사용자 인터페이스 코드를 구조화하는 것을 해보겠습니다.

컨텐츠에 대하여

이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.


Leonardo YongUk Kim

Leonardo YongUk Kim is a software developer with extensive experience in mobile and embedded projects, including: several WIPI modules (Korean mobile platform based on Nucleus RTOS), iOS projects, a scene graph engine for Android, an Android tablet, a client utility for black boxes, and some mini games using Cocos2d-x.

4 design patterns for a RESTless mobile integration »

close