RxJava - Create 함수

컴퓨터공부/안드로이드 2019.08.11 13:36 Posted by 아는 개발자 아는 개발자

앞서 작성한 포스트에선 Observable의 역할이 어떤 데이터를 Observer가 처리할 수 있도록 포장해주는 역할 이라고 설명했다. Observable은 데이터를 관찰 할 수 있는 형태로 만들 기 위해 여러 가지 오퍼레이터 함수를 가지고 있다. 이번 포스트에선 이중에서 대표적으로 사용되는 것들만 소개해보려고 한다.


1. create


백그라운드 스레드에서 옵저버가 처리할 넘겨주는 방법. 아래 코드를 보면 create 함수의 인자로 익명 ObservableOnSubscribe 클래스를 선언하고 이 안의 오버라이드 함수 인자인 emitter 변수에 onNext로 0~9까지 값을 넣어 호출 하는 것을 볼 수 있다.


Observable<Integer> observable = Observable
        .create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                Log.d(TAG, "subscribe: " + Thread.currentThread().getName());

                for (int i = 0; i < 10; i++) {
                    if (!emitter.isDisposed())
                        emitter.onNext(i);
                }

                if (!emitter.isDisposed())
                    emitter.onComplete();
            }
        })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread());

observable.subscribe(new Observer<Integer>() {
    @Override
    public void onNext(Integer integer) {
        Log.d(TAG, "onNext: " + integer);
    }
});


실행결과 아래와 같은 로그가 출력된다. 0~9까지 값이 옵저버에게 전달 됐다. 추가적으로 subscribe에서 돌고 있는 쓰레드 이름을 출력해보니 RxCachedThreadScheduler-1이란 것이 출력됐다. 이는 subscribeOn 함수에 백그라운드 함수중 하나인 Schedulers.io()를 넣었기 때문이다. 이 함수를 사용하면 Observable한 데이터를 만드는 작업을 백그라운드에서 실행 할 수 있게 된다.



2. just 


최대 10개까지의 배열 데이터를 Observable하게 만들 수 있는 함수. 그런데 10개로 제한돼서 배열을 전달하는 경우는 없고 단일 데이터를 전달 할 때 주로 사용된다.


Observable<Integer> observable = Observable
        .just(1,2,3)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread());

observable.subscribe(new Observer<Integer>() {
    @Override
    public void onNext(Integer integer) {
        Log.d(TAG, "onNext: " + integer);
    }
});


이 함수를 실행해보면 다음과 같은 로그가 나온다.



3. range 


범위를 지정해주는 방법. for문을 생성 함수의 하나로 뒀다고 생각하면 쉽다. 단 range 함수를 사용하면 map같은 형변환 오퍼레이터를 사용하지 않으면 옵저버에선 Integer의 형태로 값을 받게 된다.


Observable<Integer> observable = Observable
        .range(0, 5)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread());

observable.subscribe(new Observer<Integer>() {
    @Override
    public void onNext(Integer integer) {
        Log.d(TAG, "onNext: " + integer);
    }
});


4. fromIterable 


이미 생성된 배열의 값을 Observable하게 바꿔주는 함수. 앞서 설명한 just는 최대 10개까지 밖에 담지 못한 반면 fromIterable은 개수에 상관 없이 모두 Observable하게 바꿔준다.


List<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(3);

Observable<Integer> observable = Observable
        .fromIterable(integers)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread());

observable.subscribe(new Observer<Integer>() {
    @Override
    public void onNext(Integer integer) {
        Log.d(TAG, "onNext: " + integer);
    }
});


'컴퓨터공부 > 안드로이드' 카테고리의 다른 글

RxJava - Create 함수  (0) 2019.08.11
RxJava - Observable, Observer  (0) 2019.08.10
안드로이드 Loader  (0) 2019.07.15
onSaveInstanceState  (0) 2019.07.15
JAVA의 static  (0) 2019.04.03
안드로이드 Service  (0) 2019.03.19

RxJava - Observable, Observer

컴퓨터공부/안드로이드 2019.08.10 14:52 Posted by 아는 개발자 아는 개발자

좀더 리액티브한(reactive) UI를 만들기 위해서 프로젝트에 RxJava, RxAndroid를 도입하면서 가장 어려웠던 점은 Observable과 Observer 클래스를 개념적으로 이해하는 것이었다. 옵저버 패턴을 응용한 라이브러리이기 때문에 익숙할 것이라고 여러 문서에서 설명하고 있는데 애초 옵저버 패턴을 많이 써보지 않았고 또 디자인 패턴 책을 여러 번 보고 난 뒤에 문서를 읽어봐도 쉽사리 와닿지 않았다.


여러 번의 블로그 방문과 삽질을 반복한 후 다행히 유튜브 강좌를 통해서 어느정도 개념을 잡을 수 있었다. 혹시나 나처럼 어려움을 겪고 계신 분은 Coding with Mitch 라는 유튜브 채널 강좌를 들어보시면 도움이 될 것 같다. 모두 듣고 소화하는데 하루 정도 소요되는데 개인적으로 충분히 들어볼만한 강좌였다.


서론이 너무 길었다. 아무튼 이번 포스트에선 앞서 말한 Observable과 Observer 클래스를 개념적으로 정리해보려고 한다. 개인 공부를 위해 정리한 글인 만큼 다른 블로그이나 문서에서 설명한 것과 차이가 있을 수 있을 것 같은데 혹시나 이 글을 읽으신 분들은 이점 참고하셨으면 좋겠다.


1. Observable


이 클래스에 포함된 함수는 매우 다양하나 어떤 데이터를 관찰 할 수 있는 형태로 바꾸는 것이 이 클래스의 기본적인 임무다. Observable의 의미인 '관찰 할 수 있는'을 생각해보면 이 클래스가 어떤 일을 해야하는지 짐작 할 수 있을 것이다. 이 클래스는 개념적으로는 어떤 데이터를 Observer가 처리할 수 있도록 포장하는 작업을 담당한다고 보면 이해하기엔 편하다. 추가적인 기능으로는 값을 변형시키고 다른 타입으로 바꾸기도 하고... 등등 많은데 일단 이 정도만 이해하도록 하자.


2. Observer


스타크래프트의 정찰용 옵저버 유닛을 생각하면 이해하기 어려워진다. 게임 유닛은 잊고 순수 의미인 '관찰자'의 의미에서 보면 Observer는 Observable에서 관찰 할 수 있는 형태로 전달한 데이터를 받고 이에 대한 행동을 취한다. 전달 받은 데이터를 가지고 화면 UI를 업데이트 하든지 아니면 어떤 인자를 서버에 요청해보는지 등등.. 최종적으로 처리할 작업은 이 클래스에서 담당한다


3. Observable & Observer Diagram


출처: 깃헙


위 그림을 보면 ObservableonNext, onComplete, onError 같은 함수를 통해 Observer에게 무언가를 전달하고 있는 것을 볼 수 있다. onNext는 데이터를 포장할 때마다  Observer에게 완료된 작업물을 전달하는 것이고 onComplete는 포장 작업이 끝날 때 호출하는 함수다. onError는 Observable 내에서 어떤 문제가 생겼을 때 호출되는 함수다.


4. 코드 


아래 코드를 보면 Observable 이라는 변수는 String형태의 Observable 클래스 타입이다. 앞서 설명한 내용 대로라면 Observable은 String 형태의 데이터 타입을 Observable 하게 만들어야 한다. 이를 위해 just라는 함수를 통해 관찰할 수 있는 형태로 포장할 값으로 "selfish"와 "developer"를 넣었다. subscribeOn과 observeOn 함수는 어떤 쓰레드에서 작업을 실행할 지 정하는 함수인데 이번 포스트와는 관련이 없으니 일단 무시하자.


선언 후 subscribe 함수 내에 익명의 Observer 객체를 선언했다. 이는 만들어둔 Observable과 Observer를 매핑하는 함수다. Observer 객체를 보면 onNext, onComplete 처럼 앞의 그림에서 설명한 함수들이 등장한다. Observable에서 전달 받은 작업을 처리하기 위한 함수들이다.


Observable<String> observable = Observable
        .just("selfish", "developer")
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread());

observable.subscribe(new Observer<String>() {
    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(String s) {
        Log.d(TAG, "onNext: " + s);

    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onComplete() {
        Log.d(TAG, "onComplete: ");
    }
});


위 코드를 안드로이드 에뮬레이터로 실행해보면 다음과 같은 로그가 나온다.




'컴퓨터공부 > 안드로이드' 카테고리의 다른 글

RxJava - Create 함수  (0) 2019.08.11
RxJava - Observable, Observer  (0) 2019.08.10
안드로이드 Loader  (0) 2019.07.15
onSaveInstanceState  (0) 2019.07.15
JAVA의 static  (0) 2019.04.03
안드로이드 Service  (0) 2019.03.19

안드로이드 Loader

컴퓨터공부/안드로이드 2019.07.15 21:20 Posted by 아는 개발자 아는 개발자

앞선 포스트에서 onSaveInstanceState 콜백을 통해 화면을 전환하는 경우에도 데이터를 저장할 수 있는 방법을 배웠다. 그런데 AsyncTask 처럼 진행중인 작업에 대해서는 데이터를 저장할 수 있는 기능이 무의미할 것이다. 어디까지 데이터 작업을 처리 했으니 이때부터 다시 시작하라고 세세하게 할 수도 없는 노릇이고.


그래서 안드로이드에서는 Loader라는 라이브러리를 뒀다. 공식 문서에서는 FragmentActivity에 넣을 디스플레이 소스를 로드할 수 있는 기능으로 소개되고 있는데 일단은 별도의 쓰레드에서 돌아 Activity 생성 주기에 영향을 받지 않는 컴포넌트 정도로 이해하면 될 것 같다. 사용법은 아래와 같다.


1. implements LoaderManager.LoaderCallbacks<String>


MainActivity는 Loader API를 사용하는 Activity임을 명시 해둬서 Loader 콜백 함수들을 호출하도록 만든다.

public class MainActivity extends AppCompatActivity implements
        LoaderManager.LoaderCallbacks<string> { {

2. public Loader<String> onCreateLoader 


Activity에서 사용할 Loader 객체를 생성하는 콜백 함수를 구현한다. Loader는 AsyncTaskLoader와 CursorLoader가 있는데 CursorLoader 의 경우에는 DB에서 값을 읽어올 때 사용하고 AsyncTaskLoader 는 좀더 범용적으로 사용된다. 


2.1 protected void onStartLoading()


AsyncTaskLoader 가 생성 되면서 가장 먼저 실행되는 함수다. AsyncTask의 onPreExecute() 의 역할을 하는 것과 비슷하다. 백그라운드 작업 실행 하기 전에 필요한 셋팅 작업을 여기에 넣는다.


2.2 public String loadInBackground()


백그라운드 작업을 실행하는 함수다. 이름을 보면 감이 오겠지만  AsyncTask의 doInBackground(Void... voids)  와 동일한 기능을 하는 함수다. 반환 타입으로 세팅된 String은 결과 값의 타입이며 앞서 콜백을 implements 할 때 어떤 타입을 넣느냐에 따라 바꿀 수 있다.


2.3 public deliverResult(String result)


결과 값을 전달하는 함수다. 이 함수내에는 반드시 super.deliverResult(result);  가 포함되어 있어야지 결과 값이 최종적으로 전달 된다. 인자인 result 는 loadInBackground()에서 반환한 값이다


3. public void onLoadFinished(Loader<String> loader, String data)


AsyncTaskLoader 작업이 끝난 후에 불리는 함수이며 함수의 인자로 결과 값을 전달 받는다.  결과값을 화면에 업데이트 할 때 이 콜백 함수 내에 작업을 넣는다.


4. initLoader,restartLoader


생성한 Loader가 실행 될 수 있도록 호출한다. 아래 코드는 initLoader,restartLoader 함수를 실행한 예제 코드다.


LoaderManager loaderManager = getSupportLoaderManager();
Loader<string> searchLoader = loaderManager.getLoader(SEARCH_LOADER);
if (searchLoader == null) {
    loaderManager.initLoader(SEARCH_LOADER, queryBundle, this);
} else {
    loaderManager.restartLoader(SEARCH_LOADER, queryBundle, this);
}

함수의 첫번째 인자 값은 ID다. Loader마다 가지고 있는 고유한 Key값에 해당한다. 두번째 인자 값은 Bundle형태의 데이터 값이다. AsyncTaskLoader에게 이 데이터 값을 통해 값을 전달 할 수 있다. 세번째는 콜백함수다. 현재는 Activity가 Loader 콜백 함수를 구현해뒀기 때문에 this로 입력했다.

'컴퓨터공부 > 안드로이드' 카테고리의 다른 글

RxJava - Create 함수  (0) 2019.08.11
RxJava - Observable, Observer  (0) 2019.08.10
안드로이드 Loader  (0) 2019.07.15
onSaveInstanceState  (0) 2019.07.15
JAVA의 static  (0) 2019.04.03
안드로이드 Service  (0) 2019.03.19

onSaveInstanceState

컴퓨터공부/안드로이드 2019.07.15 20:39 Posted by 아는 개발자 아는 개발자

onCreate() onDestroy() 는  애플리케이션이 생성될 때와 종료 될 때 한 번씩만 불리는 콜백 함수로 알려져 있지만 디바이스의 설정 값이 갑자기 바뀌어 화면을 처음부터 새로 그려줘야 할 때도 불린다. 대표적으로 스마트폰을 회전 시키는 경우(rotate)가 이에 해당한다. 



확인해보기 위해 테스트 애플리케이션의 콜백 함수들에 로그를 넣고 에뮬레이터(오레오 8.1) 에 설치한 후 오른쪽으로 회전 해봤다. onPause() 함수부터 불리는 부분이 회전 후에 나온 로그며 이중에는 onCreate() onDestroy()도 포함되어 있다.


onCreate() onDestroy() 함수가 다시 불린다는 뜻은 회전하기 전까지 설정해둔 변수 값들이 모두 초기화 된다는 것을 의미하기도 한다. 만약 애플리케이션 화면에 특정 값을 바꾼 상태로 회전을 했다면 처음 애플리케이션을 실행한 상태로 화면이 바뀌기 때문에 지금까지 작업한 것들이 모두 날라가게 된다.


안드로이드에선 이런 상황을 대처하기 위해 onSaveInstanceState(Bundle outState) 라는 콜백 함수를 뒀다. 이 함수는 모든 인자들이 초기화 되는 onDestroy() 함수 호출 전에 실행되며 함수의 인자에 key-value로 여러가지 데이터를 넣을 수 있다. 변경된 인자는 최종적으로 onCreate(Bundle savedInstanceState) 함수의 인자 값으로 전달 된다.


구구절절히 코드로 보는 것이 더 이해하기 쉬울 것 같다. 먼저 onSaveInstanceState 함수내에 아래와 같이 임의의 문자열 데이터 값을 입력했다.

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    logAndAppend("onSaveInstanceState");

    outState.putString(SAVE_INSTANCE_KEY,
            "onSaveInstanceState is called!\n");
}

그리고  onCreate 함수에선 인자에 key 값이 저장되어 있는지 확인 한 후 있으면 그 값을 TextView에 표시하도록 했다. 

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mLifecycleDisplay = (TextView) findViewById(R.id.tv_lifecycle_events_display);

    if (savedInstanceState != null
            && savedInstanceState.containsKey(SAVE_INSTANCE_KEY)) {
        String savedString = savedInstanceState.getString(SAVE_INSTANCE_KEY);
        mLifecycleDisplay.setText(savedString);
    }
    logAndAppend(ON_CREATE);
}

그 결과 아래와 같이 회전 후 TextView에 로그 메시지가 추가되는 것을 확인 할 수 있었다



'컴퓨터공부 > 안드로이드' 카테고리의 다른 글

RxJava - Observable, Observer  (0) 2019.08.10
안드로이드 Loader  (0) 2019.07.15
onSaveInstanceState  (0) 2019.07.15
JAVA의 static  (0) 2019.04.03
안드로이드 Service  (0) 2019.03.19
AsyncTask  (0) 2019.03.13

오픈소스 라이센스 정리

컴퓨터공부/오픈소스 2019.06.09 11:04 Posted by 아는 개발자 아는 개발자

오픈소스를 이용해서 개발하는 경우 코드를 무료로 보고 사용할 수 있어 개발하기 편리하다는 장점이 있으나 사용하고 있는 오픈소스가 어떤 라이센스를 가지느냐에 따라서 상업적인 이용이 제한될 수도 있고 내가 만든 코드를 공개해야 할 의무까지 생길 수 있다. 이런 경우를 예방하려면 개발하기 전부터 사용할 오픈소스 라이센스에 대해 검토해둘 필요가 있다. 이번 포스트에서는 유명한 오픈소스 라이센스들에 대해서 간단히 정리를 해보려고 한다.


0. 라이센스란? 


소프트웨어의 지적 재산권을 일컫는 말이다. 음악의 저작권과 비슷한 개념 정도로 생각하면 될 것 같다. 처음 코딩에 입문하는 사람들은 남들이 짠 코드랑 본인이 짠 것과 함수와 변수 명만 제외하면 거의 차이가 없어(헬로 월드 수준이니까) 딱히 저작권이라고 할만한 것이 있는지도 모르겠고 또 수만줄이 넘는 코드에서 카피 유무의 확인조차 불가능 할 것 같은 소프트웨어에 지적 재산권이 통용되고 있다는 것에 의문을 품기도 하지만 실제 소프트웨어 업계에선 엄연히 라이센스 규정에 따라서 운영되고 있으며 이미 몇가지 판례를 통해 법적인 효력까지 갖추고 있기 때문에 쉽게 무시해선 안된다



사용하고 있는 오픈소스가 어떤 라이센스를 쓰고 있는지 확인하려면 소스코드 파일의 맨위 주석을 보면 된다. 어떤 이유인지는 모르겠으나 거의 대부분의 라이센스가 파일 최상단에 명시돼 있다. 위 그림은 리눅스 커널 파일중 하나를 gedit으로 열어본 사진이다. 이 파일은 GNU 라이센스를 사용하고 있다.


1. GPL 라이센스


소스코드 공개 필요 O, 동일한 라이센스 적용 O, 상업적이용 O


GNU라고도 불리는 이 라이센스는 리눅스 커널에 기본 라이센스로 채택되면서 개발자 사이에선 유명한(악명높은) 라이센스가 됐다.. 이 라이센스는 오픈소스의 철학에 기초해서 만들어진 것이기 때문에 '자유를 누린 만큼 너의 코드도 공개해!' 원칙을 가지고 있다. 이 라이센스를 이용해서 만든 소프트웨어는 동일한 GPL 라이센스를 사용해야하고 모두 코드를 공개해야 한다. '내가 얘네 썼는지 어떻게 알겠어' 하면서 무시할 수도 있지만 이미 판례를 통해 법적인 효력까지 갖춘 라이센스이기 때문에 사용할 때는 신중해야 한다. 자세한 내용은 나무위키 전염성 조항 참고하면 좋다. 리눅스 커널 기반 안드로이드 폰 제조사들이 다른 코드는 몰라도 리눅스 커널 소스코드는 공개할 수 밖에 없는 것은 GPL 라이센스 덕분이다.


2. BSD 라이센스


소스코드 공개 필요 X, 동일한 라이센스 적용 X, 상업적 이용 O 


BSD는 자유 소프트웨어 저작권의 한가지로 BSD계열(미국 캘리포니아 대학 버클리에서 개발한 운영체제인 유닉스)에서 주로 채택하고 있는 라이센스다. 규정은 앞서 언급한 GPL과 확연하게 다른데 이 오픈소스 라이센스를 가진 코드는 자유롭게 사용할 수 있고 소스코드를 공개 하지도 않아도 되며 돈받고 팔아도 된다. BSD에서 눈여겨 볼 만한 것은 다루는 것은 누구나 자신의 용도로 사용할 수는 있지만 이 소프트웨어를 사용해서 발생 가능한 모든 리스크와 손해는 본인이 책임지도록 하고 있다. 책임 도피형 라이센스다.


3. MIT 라이센스


소스코드 공개 필요 X, 동일한 라이센스 적용 X, 상업적 이용 O


라이센스 이름에서 추측할 수 있듯이 매사추세스 공과대학에서 만든 소프트웨어 라이센스다. BSD를 기초해서 만든 라이센스라 거의 규정은 똑같다. 소스코드를 공개할 필요도 없고 동일한 라이센스를 적용할 필요도 없으며 이 소프트웨어를 사용해서 발생할 수 있는 손해에 대해서도 책임을 지지 않는다는 것 까지 동일하다. BSD 계열의 소프트웨어에서 일반 소프트웨어로 옮겨오기 위해 만든 라이센스 정도로 생각하면 될 것 같다.


4. Apache 라이센스 


소스코드 공개 필요 X, 동일한 라이센스 적용 X, 상업적 이용 O 


아파치(Apache) 소프트웨어 재단에서 자체적으로 만든 라이센스다. 안드로이드 프레임워크쪽의 대부분의 라이브러리가 이 라이센스 규정을 따르고 있다. BSD와 거의 규정이 동일해 소스코드를 공개할 필요가 없다. 차이점이 있다면 Apache 라이센스는 특허권 측면에서 좀더 완성도를 높여서 Apache 라이센스로 출원한 특허에 대해서는 소스코드 사용자에게 특허의 무제한적 사용을 허가한다는 규정을 담고 있다. 즉 어떤 소프트웨어가 아파치 라이센스를 채택해서 배포했다면 그 소프트웨어가 특허출원이 되어 있어도 사용자에게 특허 사용료를 요구할 수 없다는 뜻이다. 나무위키에 따르면 소스코드를 무료로 공개해놓고 그걸 빌미 삼아 특허권 소송을 제기하는 더티한 플레이를 막기 위한 규정이라 한다. 이런 법적인 안전장치까지 있어서 개발자들이 가져다가 쓸 때 가장 선호하는 라이센스 중에 하나인 것 같다.


5. 추가로 


상세한 규정을 알고 싶으신 분들은 블로그 사이트를 찾는 것보다 정보통신산업 진흥원에서 만든 책자를 보는 것이 도움이 될 것 같다. https://www.oss.kr/oss_license 사이트에 가면 라이센스 가이드를 다운로드 받을 수 있다. 법적인 문제와 연관 될 수 있으니 가능하면 전문가와 상담하는 것이 좋을 것 같다.

'컴퓨터공부 > 오픈소스' 카테고리의 다른 글

오픈소스 라이센스 정리  (0) 2019.06.09
FFmpeg  (0) 2018.10.31
자동차시장 오픈소스 - 2  (0) 2017.01.31
자동차 시장 오픈소스 - 1  (0) 2017.01.15
이런 오픈 소스도 있다!  (0) 2017.01.07
오픈소스 시작하기  (0) 2017.01.01