2017년 6월 4일 일요일

[STUDY] Android Shortcut & Badge (ShortcutBadger 라이브러리 소개)

[목차]======================================================
1. Android 아이콘 뱃지 관련 라이브러리
  1) 오픈소스 주소
  2) 사용법
2. Android 아이콘 뱃지 관련된 게시글 참고(주소 펴옴)
===========================================================

1. Android 아이콘 뱃지 관련 라이브러리
  1) 오픈소스 주소
https://github.com/leolin310148/ShortcutBadger

  2) 사용법
  • Add mavenCentral to your build script.
    repositories {
        mavenCentral()
    }
  • Add dependencies for ShortcutBadger, it's available from maven now.
    dependencies {
        compile "me.leolin:ShortcutBadger:1.1.16@aar"
    }
  • Add the codes below:
    int badgeCount = 1;
    ShortcutBadger.applyCount(context, badgeCount); //for 1.1.4+
    ShortcutBadger.with(getApplicationContext()).count(badgeCount); //for 1.1.3
  • If you want to remove the badge
    ShortcutBadger.removeCount(context); //for 1.1.4+
    ShortcutBadger.with(getApplicationContext()).remove();  //for 1.1.3
or
    ShortcutBadger.applyCount(context, 0); //for 1.1.4+
    ShortcutBadger.with(getApplicationContext()).count(0); //for 1.1.3 


2. Android 아이콘 뱃지 관련된 게시글 참고(주소 펴옴)
[안드로이드 아이콘 뱃지 완전분해]
=>  Android 아이콘 뱃지에 대한 분석 및 기본 개발에 대한 의견 참고
https://medium.com/marojuns-android/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%95%84%EC%9D%B4%EC%BD%98-%EB%B1%83%EC%A7%80-%EC%99%84%EC%A0%84%EB%B6%84%ED%95%B4-c27028014e4d


출처 : 인터넷에서 검색하여 필요한 정보를 다양한 사이트에서 종합하여 작성된 것입니다. 많은 사이트 내용을 종합하여 공부하여 작성하다보니 일일이 나열하지 못하였습니다. ㅈㅅ(_ _) 이글은 자유롭게 퍼 가셔서 도움이 되었으면 좋겠습니다. 감사합니다. 

[STUDY] Butter Knife (버터나이프 - 특징 / 사용법 / 기능 / 라이센스 등)

[ButterKnife 목차]
====================================
1. ButterKnife의 특징
2. 사용법1) Gradle 파일 설정
2) ButterKnife 라이브러리 bind
3. 기능1) View를 담을 변수를 선언
2) View Lists
3) Listener Binding (onClickListener)
4) Resource Binding
5) Non-Activity Binding
6) Binding Reset
7) Adapter
8) Multi-Method Listeners
9) Optional Bindings
10) ETC
4. License
====================================


1. ButterKnife의 특징
1) 필드나 메소드를 안드로이드 뷰에 어노테이션(@)을 이용하여 편하게 접근할 수 있도록 도와주는 안드로이드 라이브러리
 => ButterKnife 공식 홈페이지 https://github.com/JakeWharton/butterknife
2) 다수의 안드로이드 개발자들과 협업할때 View, Resource를 바인딩 하는 convention을 제공
 => 코드의 가독성 및 View ID 검색 및 효율성을 높여주는데 참 좋은것 같음

※ 자바 어노테이션(Annotation, @)이란?

2. 사용법
1) Gradle 파일 설정
build.gradle 파일을 열어 dependencies를 추가해주시면 라이브러리 추가

 dependencies {
    compile 'com.jakewharton:butterknife:7.0.1'}

2) ButterKnife 라이브러리 bind
onCreate메서드에서 setContentView(LayoutID);를 한 후에, 바인드를 해주어야 함
 Butternife.bind(this);


3. 기능
1) View를 담을 변수를 선언
이때까지 귀찮게, findViewById(viewID)를 하는 것을 내부적으로 ButterKnife가 도와주게 됨
@Bind(R.id.tv_info) TextView tv_info;
@Bind(R.id.btn_method) Button btn_method;
@Bind(R.id.btn_listener) Button btn_listener;
@Bind(R.id.btn_implements) Button btn_implements;

 class ExampleActivity extends Activity {
  
@BindView(R.id.title) TextView title;
  
@BindView(R.id.subtitle) TextView subtitle;
  
@BindView(R.id.footer) TextView footer;

  
@Override public void onCreate(Bundle savedInstanceState) {
    
super.onCreate(savedInstanceState);
    setContentView
(R.layout.simple_activity);
    
ButterKnife.bind(this);
    
// TODO Use fields...
  
}
}

2) View Lists
여러 View를 (예제에서는 EditText) List로 관리하는 예제입니다. View들을 List에 담아 놓고 ButterKnife.apply()함수로 속성값을 일괄 적용하는 모습을 보여주고 있는데요 DISABLE, ENABLED와 같은 interface가 어떻게 되어 있는지 구현부 까지 보여주고 있습니다.
 // You can group multiple views into a List or array.
@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;

// The apply method allows you to act on all the views in a list at once.
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);

// Action and Setter interfaces allow specifying simple behavior.
static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {
    @Override
    public void apply(View view, int index) {
        view.setEnabled(false);
    }
};
static final ButterKnife.Setter<View, Boolean> ENABLED = new ButterKnife.Setter<View, Boolean>() {
    @Override
    public void set(View view, Boolean value, int index) {
        view.setEnabled(value);
    }
};

// An Android Property can also be used with the apply method.
ButterKnife.apply(nameViews, View.ALPHA, 0.0f);


3) Listener Binding (onClickListener)
@OnClick(R.id.btn_method)
void methodButtonClick() {
}

@OnClick(R.id.btn_listener)
void listenerButtonClick() {
}

@OnClick(R.id.btn_implements)
void implementsButtonClick() {
}


 @OnClick({R.id.btn_method, R.id.btn_listener, R.id.btn_implements})
void buttonEvents(View v) {
 //이벤트를 처리할 로직...
}

4) Resource Binding
Bind pre-defined resources with @BindBool@BindColor@BindDimen@BindDrawable@BindInt@BindString, which binds an R.bool ID (or your specified type) to its corresponding field.
 class ExampleActivity extends Activity {
  
@BindString(R.string.title) String title;
  
@BindDrawable(R.drawable.graphic) Drawable graphic;
  
@BindColor(R.color.red) int red; // int or ColorStateList field
  
@BindDimen(R.dimen.spacer) Float spacer; // int (for pixel size) or float (for exact value) field
  
// ...
}

5) Non-Activity Binding
You can also perform binding on arbitrary objects by supplying your own view root.
 public class FancyFragment extends Fragment {
  
@BindView(R.id.button1) Button button1;
  
@BindView(R.id.button2) Button button2;

  
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
    
ButterKnife.bind(this, view);
    
// TODO Use fields...
    
return view;
  
}
}

6) Binding Reset
Fragments have a different view lifecycle than activities. When binding a fragment in onCreateView, set the views to null in onDestroyView. Butter Knife returns an Unbinder instance when you call bind to do this for you. Call its unbind method in the appropriate lifecycle callback
 public class FancyFragment extends Fragment {
  
@BindView(R.id.button1) Button button1;
  
@BindView(R.id.button2) Button button2;
  
private Unbinder unbinder;

  
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
    unbinder 
= ButterKnife.bind(this, view);
    
// TODO Use fields...
    
return view;
  
}

  
@Override public void onDestroyView() {
    
super.onDestroyView();
    unbinder
.unbind();
  
}
}

7) Adapter
Another use is simplifying the view holder pattern inside of a list adapter

public class MyAdapter extends BaseAdapter {
  
@Override
  public View getView(int position, View view, ViewGroup parent) {
    
ViewHolder holder;
    
if (view != null) {
      holder 
= (ViewHolder) view.getTag();
    
} else {
      view 
= inflater.inflate(R.layout.whatever, parent, false);
      holder 
= new ViewHolder(view);
      view
.setTag(holder);
    
}

    holder
.name.setText("John Doe");
    
// etc...

    
return view;
  
}

  
static class ViewHolder {
    
@BindView(R.id.title) TextView name;
    
@BindView(R.id.job_title) TextView jobTitle;

    
public ViewHolder(View view) {
      
ButterKnife.bind(this, view);
    
}
  
}
}

8) Multi-Method Listeners
Method annotations whose corresponding listener has multiple callbacks can be used to bind to any one of them. Each annotation has a default callback that it binds to. Specify an alternate using the callback parameter.
 @OnItemSelected(R.id.list_view)
void onItemSelected(int position) {
  
// TODO ...
}
@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)
void onNothingSelected() {
  
// TODO ...
}

9) Optional Bindings

@Nullable 
@BindView(R.id.might_not_be_there) TextView mightNotBeThere;
@Optional 
@OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
  
// TODO ...
}

10) ETC
Also included are findById methods which simplify code that still has to find views on a View, Activity, or Dialog. It uses generics to infer the return type and automatically performs the cast.
View view = LayoutInflater.from(context).inflate(R.layout.thing, null);
TextView firstName = ButterKnife.findById(view, R.id.first_name);
TextView lastName = ButterKnife.findById(view, R.id.last_name);
ImageView photo = ButterKnife.findById(view, R.id.photo);

Add a static import for ButterKnife.findById and enjoy even more fun.

4. License
Copyright 2013 Jake Wharton
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.






출처 : 인터넷에서 RxAndroid 검색하여 필요한 정보를 다양한 사이트에서 종합하여 작성된 것입니다. 많은 사이트 내용을 종합하여 공부하여 작성하다보니 일일이 나열하지 못하였습니다. ㅈㅅ(_ _) 이글은 자유롭게 퍼 가셔서 도움이 되었으면 좋겠습니다. 감사합니다. 

[STUDY] RxAndroid Part 9 (Connectable Observable )

[목차]==================================================
1. Connectable Observable 정의 
2. Connectable Observable 사용 예제
======================================================


1. Connectable Observable 정의
 Connectable Observable은 구독을 하더라도 이템 방출을 시작하지 않는다는 점을 제외하면 일반적인 Observable과 비슷합니다. connect()을 호출했을 때에만 방출합니다. 이 방법으로 Subscriber들에게 Observable가 방출을 시작하기전에 Observable구독하도록 기다릴 수 있습니다.
  • ConnectableObservable.connect( ) — Connectable Observable에게 아이템 방출을 시작하라고 지시한다.
  • Observable.publish( ) — Observable을 Connectable Observable으로 변형시킨다.
  • Observable.replay( ) — 모든 Observer들에게 방출이 시작된 후에 구독을 했을 경우라도 같은 순서의 방출된 아이템을 볼 수 있도록 보장합니다.
  • ConnectableObservable.refCount( ) — Connectable Observable을 일반적인 Observable처럼 작동하도록 만듭니다.

 
2. Connectable Observable 사용 예제
아래의 예제코드는 같은 Observable을 구독하는 두개의 subscriber를 보여주는 코드입니다. 첫번째 케이스에서는 일반적인 Observable이고 두번째 케이스에서는 Connectable Observable으로 subscriber가 모두 구독한 이후 연결하였습니다.
 Observable firstMillion  = Observable.range( 1, 1000000 ).sample(7, java.util.concurrent.TimeUnit.MILLISECONDS);

firstMillion.subscribe(
   { println("Subscriber #1:" + it); },       // onNext
   { println("Error: " + it.getMessage()); }, // onError
   { println("Sequence #1 complete"); }       // onCompleted
);

firstMillion.subscribe(
    { println("Subscriber #2:" + it); },       // onNext
    { println("Error: " + it.getMessage()); }, // onError
    { println("Sequence #2 complete"); }       // onCompleted
);
Subscriber #1:211128
Subscriber #1:411633
Subscriber #1:629605
Subscriber #1:841903
Sequence #1 complete
Subscriber #2:244776
Subscriber #2:431416
Subscriber #2:621647
Subscriber #2:826996
Sequence #2 complete

 Observable firstMillion  = Observable.range( 1, 1000000 ).sample(7, java.util.concurrent.TimeUnit.MILLISECONDS).publish();

firstMillion.subscribe(
   { println("Subscriber #1:" + it); },       // onNext
   { println("Error: " + it.getMessage()); }, // onError
   { println("Sequence #1 complete"); }       // onCompleted
);
firstMillion.subscribe(
   { println("Subscriber #2:" + it); },       // onNext
   { println("Error: " + it.getMessage()); }, // onError
   { println("Sequence #2 complete"); }       // onCompleted
);
firstMillion.connect();
Subscriber #2:208683
Subscriber #1:208683
Subscriber #2:432509
Subscriber #1:432509
Subscriber #2:644270
Subscriber #1:644270
Subscriber #2:887885
Subscriber #1:887885
Sequence #2 complete
Sequence #1 complete



출처 : 인터넷에서 RxAndroid 검색하여 필요한 정보를 다양한 사이트에서 종합하여 작성된 것입니다. 많은 사이트 내용을 종합하여 공부하여 작성하다보니 일일이 나열하지 못하였습니다. ㅈㅅ(_ _) 이글은 자유롭게 퍼 가셔서 도움이 되었으면 좋겠습니다. 감사합니다.

[STUDY] RxAndroid Part 8 (Error 핸들링 방법)


[목차]==================================================
1. onError 해주지 않으면 Crash가 발생 주의
2. subscribe 에서 에러 처리
3. Error 캐치 - onErrorReturn
4. Error 캐치 - OnErrorResumeNext
5. Retry
6. Retry 횟수 제한
7. RetryWhen
======================================================


RxJava & RxAndroid 사용 시 항상 에러 핸들러를 구독하고 제공하는지 항상 확인해야 합니다. 그렇지 않으면 특히 Scheduler를 적용할 때 스택 트레이스에 아무것도 없을 수 있습니다. 물론 RxJava & RxAndroid 에서 뭔가 잘못됐다고 알려주긴 하지만 어디서 발생했는지 찾을 방법이 없습니다. 항상 에러 콜백을 사용하고, 에러가 발생한다면 에러를 로그로 남겨서 예상치 못한 오류를 기록해야 합니다.

1. onError 해주지 않으면 Crash가 발생 주의
 Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> subscriber) throws Exception {
                log("subscribe");
                subscriber.onNext("emit 1");
                subscriber.onNext("emit 2");
                subscriber.onError(new Throwable());
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                log("on next: " + s);
            }
        });

2. subscribe 에서 에러 처리

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> subscriber) throws Exception {
                log("subscribe");
                subscriber.onNext("emit 1");
                subscriber.onNext("emit 2");
                subscriber.onError(new Throwable());
            }
        }).subscribe(new DefaultObserver<String>() {
            @Override
            public void onNext(String value) {
                log("on next: " + value);
            }
            @Override
            public void onError(Throwable e) {

                // 에러시 처리를 여기로 받음
                log("error:" + e);
            }
            @Override
            public void onComplete() {
                log("completed");
            }
        });
[출력결과]
subscribe
on next: emit 1
on next: emit 2
error:java.lang.Throwable

3. Error 캐치 - onErrorReturn
Observable 체인 안에서 발생한 Error 를 캐치해서, 대체할 Object로 변환하는 것으로 subscriber에 Error가 전달되는 것을 막을 수 있다.
 Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> subscriber) throws Exception {
                log("subscribe");
                subscriber.onNext("emit 1");
                subscriber.onNext("emit 2");
                subscriber.onError(new Throwable());            }
        }).onErrorReturn(new Function<Throwable, String>() {
            @Override
            public String apply(Throwable throwable) throws Exception {
                return "return";
            }
        }).subscribe(new DefaultObserver<String>() {
            @Override
            public void onNext(String value) {
                log("on next: " + value);
            }
            @Override
            public void onError(Throwable e) {
                // 에러시 처리를 여기로 받음
                log("error:" + e);
            }
            @Override
            public void onComplete() {
                log("completed");
            }
        });
[출력결과]
subscribe
on next: emit 1
on next: emit 2
on next: return
completed

4. Error 캐치 - OnErrorResumeNext
Observable 체인에서 발생한 Error를 캐치해서, 그 안에서 다시 한 번 Observable를 호출하면 에러시 대체 Stream을 반환할 수 있다.
 Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> subscriber) throws Exception {
                log("subscribe");
                subscriber.onNext("emit 1");
                subscriber.onNext("emit 2");
                subscriber.onError(new Throwable());            }
        }).onErrorResumeNext(new Function<Throwable, ObservableSource<? extends String>>() {            @Override
            public ObservableSource<? extends String> apply(Throwable throwable) throws Exception {
                return Observable.fromArray(new String[]{"resume 1", "resume 2"});
            }
        }).subscribe(new DefaultObserver<String>() {
            @Override
            public void onNext(String value) {
                log("on next: " + value);
            }
            @Override
            public void onError(Throwable e) {
                // 에러시 처리를 여기로 받음
                log("error:" + e);
            }
            @Override
            public void onComplete() {
                log("completed");
            }
        });
[출력결과]
subscribe
on next: emit 1
on next: emit 2
on next: resume 1
on next: resume 2
completed

5. Retry
Error가 일어났을 때, 자동으로 subscribe를 다시 해준다.
성공할때까지 계속... 무한루프 될 가능성이 있으므로 유의해야 한다
 Observable.create(subscriber -> {
            log("subscribe");
            subscriber.onNext("emit 1");
            subscriber.onNext("emit 2");
            subscriber.onError(new Throwable());
        })
        .retry()
        .subscribe()
[출력결과]
subscribe
on next: emit 1
on next: emit 2
subscribe
on next: emit 1
on next: emit 2
subscribe
on next: emit 1
on next: emit 2
.
.
.
반복

6. Retry 횟수 제한
 Observable.create(subscriber -> {
            log("subscribe");
            subscriber.onNext("emit 1");
            subscriber.onNext("emit 2");
            subscriber.onError(new Throwable());
        })
        .retry(3)
        .subscribe()
[출력결과]
subscribe
on next: emit 1
on next: emit 2
subscribe
on next: emit 1
on next: emit 2
subscribe
on next: emit 1
on next: emit 2
subscribe
on next: emit 1
on next: emit 2
error:java.lang.Throwable

Retry 좀 더 구체적인 설정
 Observable.create(subscriber -> {
            log("subscribe");
            subscriber.onNext("emit 1");
            subscriber.onNext("emit 2");
            subscriber.onError(new Throwable());        })
        .retry(new BiPredicate<Integer, Throwable>() {
            @Override
            public boolean test(Integer integer, Throwable throwable) throws Exception {
                if (integer < 3) {
                    return true;
                }
                return throwable instanceof IllegalStateException;
            }
        })

        .subscribe(s -> log("on next: " + s)
            , e -> log("error:" + e)
            , () -> log("completed"));
[출력결과]
subscribe
on next: emit 1
on next: emit 2
subscribe
on next: emit 1
on next: emit 2
subscribe
on next: emit 1
on next: emit 2
error:java.lang.Throwable

7. RetryWhen
보다 세밀하게 retry 처리를 제어하기 위한 함수.
 Observable.create(subscriber -> {
            log("subscribe");
            subscriber.onNext("emit 1");
            subscriber.onNext("emit 2");
            subscriber.onError(new Throwable());        }).retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
            @Override
            public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
                return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(Throwable throwable) throws Exception {
                        return Observable.timer(3, TimeUnit.SECONDS);
                    }
                });
            }
        }).subscribe(s -> log("on next: " + s)
                        , e -> log("error:" + e)
                        , () -> log("completed"));
[출력결과]
subscribe
on next: emit 1
on next: emit 2
// 3초 후
subscribe
on next: emit 1
on next: emit 2
// 3초 후
subscribe
on next: emit 1
on next: emit 2
.
.
.
반복

그냥 Error인채로 종료
 Observable.create(subscriber -> {
            log("subscribe");
            subscriber.onNext("emit 1");
            subscriber.onNext("emit 2");
            subscriber.onError(new Throwable());
        }).subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(throwableObservable -> throwableObservable.flatMap(
                        throwable -> Observable.error(throwable)
                ))
.subscribe(s -> log("on next: " + s)
                , e -> log("error:" + e)
                , () -> log("completed"));

Error에 대한 처리를 하지 않고 Complete하기
 Observable.create(subscriber -> {
            log("subscribe");
            subscriber.onNext("emit 1");
            subscriber.onNext("emit 2");
            subscriber.onError(new Throwable());
        }).onErrorResumeNext(throwable -> {Observable.empty();})                .subscribe(s -> log("on next: " + s)
                , e -> log("error:" + e)
                , () -> log("completed"));
[출력결과]
subscribe
on next: emit 1
on next: emit 2
completed

3번 retry하고 종료
이 경우, 앞의 retry(count) 함수와의 차이는 retry(count)에서는 retry 횟수가 제한에 도달한 후에 error로 종료합니다만, 이 케이스는 completed 에서 종료한다는 점이다.
 Observable.create(subscriber -> {
            log("subscribe");
            subscriber.onNext("emit 1");
            subscriber.onNext("emit 2");
            subscriber.onError(new Throwable());        }).retryWhen(throwableObservable -> throwableObservable.take(3))                .subscribe(s -> log("on next: " + s)
                , e -> log("error:" + e)
                , () -> log("completed"));
[출력결과]
subscribe
on next: emit 1
on next: emit 2
subscribe
on next: emit 1
on next: emit 2
subscribe
on next: emit 1
on next: emit 2
completed

3초 retry를 3번 하고 종료하기
 Observable.create(subscriber -> {
            log("subscribe");
            subscriber.onNext("emit 1");
            subscriber.onNext("emit 2");
            subscriber.onError(new Throwable());
        }).retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
            @Override
            public ObservableSource<?> apply(@NonNull Observable<Throwable> throwableObservable) throws Exception {
                return throwableObservable.take(3).flatMap(new Function<Throwable, ObservableSource<?>>() {
                    @Override
                    public ObservableSource<?> apply(@NonNull Throwable throwable) throws Exception {
                        return Observable.timer(3, TimeUnit.SECONDS);
                    }
                });
        
    }
        }).subscribe(s -> log("on next: " + s)
                        , e -> log("error:" + e)
                        , () -> log("completed"));
[출력결과]
subscribe
on next: emit 1
on next: emit 2
// 3초 후
subscribe
on next: emit 1
on next: emit 2
// 3초 후
subscribe
on next: emit 1
on next: emit 2
completed

 


 출처 : 인터넷에서 RxAndroid 검색하여 필요한 정보를 다양한 사이트에서 종합하여 작성된 것입니다. 많은 사이트 내용을 종합하여 공부하여 작성하다보니 일일이 나열하지 못하였습니다. ㅈㅅ(_ _) 이글은 자유롭게 퍼 가셔서 도움이 되었으면 좋겠습니다. 감사합니다. 

[STUDY] RxAndroid Part 7 (Scheduler 이해하기)


[목차]==================================================
1. RxJava와 RxAndroid에서 제공하는 Scheduler 종류
1) RxJava가 제공하는 Scheduler
2) RxAndroid는 제공하는 Scheduler
2. 독립적으로 사용 가능한 Scheduler
3. 사용법 예제
1) Scheduler 안한 경우 기본 동작
2) subscribeOn() API만 사용한 경우 동작
3) observerOn() API만 사용한 경우 동작
4) subscribeOn() & observerOn() 1번씩 API 사용한 경우 동작
5) subscribeOn() & observerOn() 다수 API 사용한 경우 동작
======================================================


RxAndroid에서는 Scheduler를 통해 어느 쓰레드에서 실행이 될지 결정 할 수 있습니다.Scheduler는 subsctibeOn(), observeOn() 에서 각각 지정할 수 있는데
subsctibeOn()은 observable의 작업을 시작하는 쓰레드를 선택 할 수 있습니다.( 중복해서 적을 경우 가장 마지막에 적힌 스레드에서 시작합니다.)
observeOn()은 이후에 나오는 Operator, subscribe의 Scheduler를 변경 할 수 있습니다.

1. RxJava와 RxAndroid에서 제공하는 Scheduler 종류
1) RxJava가 제공하는 Scheduler
  • Schedulers.computation()
이벤트 룹에서 간단한 연산이나 콜백 처리를 위해서 쓰는 것입니다. I/O 처리를 여기에서 해서는 안됩니다.
RxComputationThreadPool라는 별도의 스레드 풀에서 돌아갑니다. 최대 cpu갯수 ?개의 스레드 풀이 순환하면서 실행됩니다.
  • Schedulers.from(executor)
특정 executor를 스케쥴러로 사용합니다
  • Schedulers.immediate
현재 스레드에서 즉시 수행합니다.
observeOn()이 여러번 쓰였을 경우 immediate()를 선언한 바로 윗쪽의 스레드를 따라갑니다.
  • Schedulers.io()
동기 I/O를 별도로 처리시켜 비동기 효율을 얻기 위한 스케줄러입니다. 자체적인 스레드 풀에 의존합니다.
자체적인 스레드 풀 CachedThreadPool을 사용합니다. API 호출 등 네트워크를 사용한 호출 시 사용됩니다.
  • Schedulers.newThread()
항상 새로운 스레드를 만드는 스케쥴러입니다.
  • Schedulers.trampoline()
큐에 있는 일이 끝나면 이어서 현재 스레드에서 수행하는 스케쥴러

※ 일부 오퍼레이터들은 자체적으로 어떤 스케쥴러를 사용할지 지정합니다. 예를 들어 buffer 오퍼레이터는 Schedulers.computation()에 의존하며 repeat은 Schedulers.trampoline()를 사용합니다.


2) RxAndroid는 제공하는 Scheduler
  • AndroidSchedulers.mainThread()
안드로이드의 UI 스레드에서 동작
  • HandlerScheduler.from(handler)
특정 핸들러 handler에 의존하여 동작

※ 안드로이드에 특화된 스케쥴러입니다. 보통은 RxAndroid가 제공하는 AndroidSchedulers.mainThread()와 RxJava가 제공하는 Schedulers.io()를 조합해서 Schedulers.io()에서 수행한 결과를 AndroidSchedulers.mainThread()에서 받아 UI에 반영하는 패턴등이 일반적으로 쓰입니다.


2. 독립적으로 사용 가능한 Scheduler
Scheduler는 Observable, Operator, Subscriber 모델 밖에서 별도로 사용할 수 있습니다.
 worker = Schedulers.newThread().createWorker();

worker.schedule(new Action0() {
    @Override
    public void call() {
        realmJob();
    }
});

 Scheduler.Worker worker = Schedulers.newThread().createWorker();
        worker.schedule(new Runnable() {
            @Override
            public void run() {
                log("worker: " + Thread.currentThread().getName());
            }
        });
[출력결과]
worker: RxNewThreadScheduler-1


3. 사용법 예제
1) Scheduler 안한 경우 기본 동작
Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                log("subscribe:" + Thread.currentThread().getName());
                e.onNext("next");
            }
        }).map(s1 -> {
            log("map: " + Thread.currentThread().getName());
            return s1;
        }).subscribe(s -> log("on next: " + Thread.currentThread().getName()));
[출력결과]
subscribe:main
map: main
on next: main

2) subscribeOn() API만 사용한 경우 동작
Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                log("subscribe:" + Thread.currentThread().getName());
                e.onNext("next");
            }
        }).subscribeOn(Schedulers.computation()).map(s1 -> {
            log("map: " + Thread.currentThread().getName());
            return s1;
        }).subscribe(s -> log("on next: " + Thread.currentThread().getName()));
[출력결과]
subscribe:RxComputationThreadPool-1
map: RxComputationThreadPool-1
on next: RxComputationThreadPool-1

3) observerOn() API만 사용한 경우 동작
Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                log("subscribe:" + Thread.currentThread().getName());
                e.onNext("next");
            }
        }).observeOn(Schedulers.computation()).map(s1 -> {
            log("map: " + Thread.currentThread().getName());
            return s1;
        }).subscribe(s -> log("on next: " + Thread.currentThread().getName()));
[출력결과]
subscribe:main
map: RxComputationThreadPool-1
on next: RxComputationThreadPool-1

4) subscribeOn() & observerOn() 1번씩 API 사용한 경우 동작
Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                log("subscribe:" + Thread.currentThread().getName());
                e.onNext("next");
            }
        }).subscribeOn(Schedulers.io())
              .observeOn(AndroidSchedulers.mainThread())
                .map(s1 -> {
                        log("map: " + Thread.currentThread().getName());
                        return s1;
         }).subscribe(s -> log("on next: " + Thread.currentThread().getName()));
[출력결과]
subscribe:RxCachedThreadScheduler-1
map: main
on next: main

5) subscribeOn() & observerOn() 다수 API 사용한 경우 동작
 Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                log("subscribe:" + Thread.currentThread().getName());
                e.onNext("next");
            }
        }).subscribeOn(Schedulers.io())
          .subscribeOn(Schedulers.computation())
          .observeOn(AndroidSchedulers.mainThread()).map(s1 -> {
                        log("map1: " + Thread.currentThread().getName());
                        return s1;
         }).observeOn(Schedulers.newThread()).map(s2 -> {
                        log("map2: " + Thread.currentThread().getName());
                        return s2;
         }).observeOn(Schedulers.single()).map(s3 -> {
                        log("map3: " + Thread.currentThread().getName());
                        return s3;
         }).subscribe(s -> log("on next: " + Thread.currentThread().getName()));
[출력결과]
subscribe:RxCachedThreadScheduler-1
map1: main
map2: RxNewThreadScheduler-1
map3: RxSingleScheduler-1
on next: RxSingleScheduler-1



 
출처 : 인터넷에서 RxAndroid 검색하여 필요한 정보를 다양한 사이트에서 종합하여 작성된 것입니다. 많은 사이트 내용을 종합하여 공부하여 작성하다보니 일일이 나열하지 못하였습니다. ㅈㅅ(_ _) 이글은 자유롭게 퍼 가셔서 도움이 되었으면 좋겠습니다. 감사합니다.