RxJava 만나기: Android용 누락된 반응형 프로그래밍 라이브러리

게시 됨: 2022-03-11

Android 개발자라면 RxJava에 대해 들어본 적이 있을 것입니다. Android 개발에서 반응형 프로그래밍을 활성화하기 위해 가장 많이 논의된 라이브러리 중 하나입니다. 모바일 프로그래밍에 내재된 동시성/비동기 작업을 단순화하기 위한 이동 프레임워크로 선전됩니다.

하지만... RxJava는 무엇이며 어떻게 "단순화"합니까?

Android용 함수형 반응 프로그래밍: RxJava 소개

RxJava를 사용하여 너무 많은 Java 스레드에서 Android를 풀어보세요.
트위터

RxJava가 무엇인지 설명하는 온라인 리소스가 이미 많이 있지만 이 기사에서 제 목표는 RxJava에 대한 기본 소개와 특히 RxJava가 Android 개발에 어떻게 적용되는지 설명하는 것입니다. 또한 새 프로젝트나 기존 프로젝트에 통합하는 방법에 대한 몇 가지 구체적인 예와 제안을 드리겠습니다.

RxJava를 고려하는 이유

핵심에서 RxJava는 스레딩에 대한 추상화 수준을 높이기 때문에 개발을 단순화합니다. 즉, 개발자는 다른 스레드에서 발생해야 하는 작업을 수행하는 방법에 대한 세부 사항에 대해 너무 많이 걱정할 필요가 없습니다. 이것은 스레딩이 올바르게 구현되기 어렵고 올바르게 구현되지 않으면 디버그 및 수정하기 가장 어려운 일부 버그를 유발할 수 있기 때문에 특히 매력적입니다.

물론 이것이 스레딩과 관련하여 RxJava가 방탄이라는 의미는 아니며 배후에서 무슨 일이 일어나고 있는지 이해하는 것이 여전히 중요합니다. 그러나 RxJava는 확실히 당신의 삶을 더 쉽게 만들 수 있습니다.

예를 들어 보겠습니다.

네트워크 호출 - RxJava 대 AsyncTask

네트워크를 통해 데이터를 얻고 결과적으로 UI를 업데이트하려고 한다고 가정해 보겠습니다. 이를 수행하는 한 가지 방법은 (1) Activity / Fragment 에 내부 AsyncTask 하위 클래스를 만들고, (2) 백그라운드에서 네트워크 작업을 수행하고, (3) 해당 작업의 결과를 가져와서 메인 스레드에서 UI를 업데이트하는 것입니다. .

 public class NetworkRequestTask extends AsyncTask<Void, Void, User> { private final int userId; public NetworkRequestTask(int userId) { this.userId = userId; } @Override protected User doInBackground(Void... params) { return networkService.getUser(userId); } @Override protected void onPostExecute(User user) { nameTextView.setText(user.getName()); // ...set other views } } private void onButtonClicked(Button button) { new NetworkRequestTask(123).execute() }

무해해 보이지만 이 접근 방식에는 몇 가지 문제와 제한 사항이 있습니다. 즉, NetworkRequestTask 는 내부 클래스이고 외부 클래스에 대한 암시적 참조를 보유하기 때문에 메모리/컨텍스트 누수가 쉽게 생성됩니다. 또한 네트워크 호출 후 다른 긴 작업을 연결하려면 어떻게 해야 합니까? 가독성을 크게 낮출 수 있는 두 개의 AsyncTask 를 중첩해야 합니다.

대조적으로, 네트워크 호출을 수행하기 위한 RxJava 접근 방식은 다음과 같습니다.

 private Subscription subscription; private void onButtonClicked(Button button) { subscription = networkService.getObservableUser(123) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<User>() { @Override public void call(User user) { nameTextView.setText(user.getName()); // ... set other views } }); } @Override protected void onDestroy() { if (subscription != null && !subscription.isUnsubscribed()) { subscription.unsubscribe(); } super.onDestroy(); }

이 접근 방식을 사용하여 반환된 Subscription 개체에 대한 참조를 유지함으로써 문제(외부 컨텍스트에 대한 참조를 보유하는 실행 중인 스레드로 인한 잠재적인 메모리 누수)를 해결합니다. 그런 다음 이 Subscription 객체는 Activity / Fragment 객체의 #onDestroy() 메서드에 연결되어 Activity / Fragment 를 파괴해야 할 때 Action1#call 작업이 실행되지 않도록 합니다.

또한 #getObservableUser(...) 의 반환 유형(즉, Observable<User> )이 추가 호출과 연결되어 있다는 점에 유의하세요. 이 유연한 API를 통해 AsyncTask 사용의 두 번째 문제를 해결할 수 있습니다. AsyncTask는 추가 네트워크 호출/긴 작업 연결을 허용한다는 것입니다. 꽤 깔끔하죠?

몇 가지 RxJava 개념에 대해 더 자세히 살펴보겠습니다.

관찰 가능, 관찰자 ​​및 연산자 - RxJava Core의 3가지 O

RxJava 세계에서는 모든 것이 스트림으로 모델링될 수 있습니다. 스트림은 시간이 지남에 따라 항목을 방출하며 각 방출은 소비/관찰될 수 있습니다.

생각해보면 스트림은 새로운 개념이 아닙니다. 클릭 이벤트가 스트림이 될 수 있고, 위치 업데이트가 스트림이 될 수 있고, 푸시 알림이 스트림이 될 수 있습니다.

RxJava 세계에서는 모든 것이 스트림으로 모델링될 수 있습니다.

스트림 추상화는 내가 "3 O"라고 부르는 3가지 핵심 구성을 통해 구현됩니다. 즉, O bservable, O bserver 및 O 연산자입니다. Observable 은 항목(스트림)을 방출합니다. 관찰자 는 해당 항목을 소비합니다. Observable 객체의 방출은 Operator 호출을 연결하여 추가로 수정, 변환 및 조작할 수 있습니다.

주목할 만한

Observable은 RxJava의 스트림 추상화입니다. 시퀀스가 주어지면 해당 항목을 순서대로 반복하고 생성한다는 점에서 Iterator 와 유사합니다. 그런 다음 소비자는 기본 시퀀스에 관계없이 동일한 인터페이스를 통해 해당 항목을 사용할 수 있습니다.

숫자 1, 2, 3을 순서대로 내보내고 싶다고 가정해 보겠습니다. 그렇게 하려면 Observable<T>#create(OnSubscribe<T>) 메서드를 사용할 수 있습니다.

 Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> subscriber) { subscriber.onNext(1); subscriber.onNext(2); subscriber.onNext(3); subscriber.onCompleted(); } });

subscriber.onNext(Integer) 를 호출하면 스트림의 항목이 방출되고 스트림 방출이 완료되면 subscriber.onCompleted() 가 호출됩니다.

Observable을 만드는 이 접근 방식은 상당히 장황합니다. 이러한 이유로 거의 모든 경우에 선호되어야 하는 Observable 인스턴스를 생성하기 위한 편리한 방법이 있습니다.

Observable을 만드는 가장 간단한 방법은 Observable#just(...) 를 사용하는 것입니다. 메서드 이름에서 알 수 있듯이 메서드 인수로 전달한 항목만 내보냅니다.

 Observable.just(1, 2, 3); // 1, 2, 3 will be emitted, respectively

관찰자

Observable 스트림의 다음 구성 요소는 구독한 Observer(또는 Observers)입니다. 관찰자는 스트림에서 "흥미로운" 일이 발생할 때마다 알림을 받습니다. 관찰자는 다음 이벤트를 통해 알림을 받습니다.

  • Observer#onNext(T) - 항목이 스트림에서 방출될 때 호출됩니다.
  • Observable#onError(Throwable) - 스트림 내에서 오류가 발생할 때 호출됩니다.
  • Observable#onCompleted() - 스트림이 항목 방출을 완료하면 호출됩니다.

스트림을 구독하려면 Observable<T>#subscribe(...) 를 호출하고 Observer 인스턴스를 전달하면 됩니다.

 Observable<Integer> observable = Observable.just(1, 2, 3); observable.subscribe(new Observer<Integer>() { @Override public void onCompleted() { Log.d("Test", "In onCompleted()"); } @Override public void onError(Throwable e) { Log.d("Test", "In onError()"); } @Override public void onNext(Integer integer) { Log.d("Test", "In onNext():" + integer); } });

위의 코드는 Logcat에서 다음을 내보냅니다.

 In onNext(): 1 In onNext(): 2 In onNext(): 3 In onNext(): 4 In onCompleted()

Observable의 방출에 더 이상 관심이 없는 경우도 있을 수 있습니다. 이것은 예를 들어 Activity / Fragment 가 메모리에서 회수되어야 하는 경우 Android에서 특히 관련이 있습니다.

항목 관찰을 중지하려면 반환된 Subscription 객체에서 Subscription#unsubscribe() 를 호출하기만 하면 됩니다.

 Subscription subscription = someInfiniteObservable.subscribe(new Observer<Integer>() { @Override public void onCompleted() { // ... } @Override public void onError(Throwable e) { // ... } @Override public void onNext(Integer integer) { // ... } }); // Call unsubscribe when appropriate subscription.unsubscribe();

위의 코드 조각에서 볼 수 있듯이 Observable을 구독할 때 반환된 구독 개체에 대한 참조를 보유하고 나중에 필요할 때 subscription#unsubscribe() 를 호출합니다. Android에서는 Activity#onDestroy() 또는 Fragment#onDestroy() ) 내에서 가장 잘 호출됩니다.

운영자

Observable에서 내보낸 항목은 구독한 Observer 객체에 알리기 전에 Operators를 통해 변환, 수정 및 필터링할 수 있습니다. 함수형 프로그래밍에서 볼 수 있는 가장 일반적인 작업(예: map, filter, reduce 등) 중 일부는 Observable 스트림에도 적용할 수 있습니다. 지도를 예로 들어 보겠습니다.

 Observable.just(1, 2, 3, 4, 5).map(new Func1<Integer, Integer>() { @Override public Integer call(Integer integer) { return integer * 3; } }).subscribe(new Observer<Integer>() { @Override public void onCompleted() { // ... } @Override public void onError(Throwable e) { // ... } @Override public void onNext(Integer integer) { // ... } });

위의 코드 조각은 Observable에서 각 방출을 가져오고 각각에 3을 곱하여 스트림 3, 6, 9, 12, 15를 각각 생성합니다. 연산자를 적용하면 일반적으로 결과로 또 다른 Observable이 반환되며, 이는 원하는 결과를 얻기 위해 여러 작업을 연결할 수 있으므로 편리합니다.

위의 스트림이 주어지면 짝수만 수신하기를 원한다고 가정해 보겠습니다. 이것은 필터 작업을 연결하여 달성할 수 있습니다.

 Observable.just(1, 2, 3, 4, 5).map(new Func1<Integer, Integer>() { @Override public Integer call(Integer integer) { return integer * 3; } }).filter(new Func1<Integer, Boolean>() { @Override public Boolean call(Integer integer) { return integer % 2 == 0; } }).subscribe(new Observer<Integer>() { @Override public void onCompleted() { // ... } @Override public void onError(Throwable e) { // ... } @Override public void onNext(Integer integer) { // ... } });

Observable 스트림을 수정하는 RxJava 도구 세트에 내장된 많은 연산자가 있습니다. 스트림을 수정하는 방법을 생각할 수 있다면 이를 위한 오퍼레이터가 있을 가능성이 있습니다. 대부분의 기술 문서와 달리 RxJava/ReactiveX 문서를 읽는 것은 매우 간단하고 핵심적입니다. 설명서의 각 연산자는 연산자가 스트림에 미치는 영향에 대한 시각화와 함께 제공됩니다. 이러한 시각화를 "대리석 다이어그램"이라고 합니다.

다음은 플립이라는 가상의 연산자가 대리석 다이어그램을 통해 모델링되는 방법입니다.

플립이라는 가상의 연산자가 대리석 다이어그램을 통해 모델링되는 방법의 예.

RxJava를 사용한 멀티스레딩

Observable 체인에서 작업이 발생하는 스레드 제어는 연산자가 발생해야 하는 스케줄러를 지정하여 수행됩니다. 기본적으로 스케줄러는 지정된 경우 운영자가 사용하고 실행하는 스레드 풀로 생각할 수 있습니다. 기본적으로 이러한 스케줄러가 제공되지 않으면 Observable 체인은 Observable#subscribe(...) 가 호출되는 동일한 스레드에서 작동합니다. 그렇지 않으면 Observable#subscribeOn(Scheduler) 및/또는 Observable#observeOn(Scheduler) 을 통해 스케줄러를 지정할 수 있습니다. 여기서 스케줄러가 선택한 스레드에서 예약된 작업이 발생합니다.

두 방법의 주요 차이점은 Observable#subscribeOn(Scheduler) 이 Observable 소스에 어떤 스케줄러를 실행해야 하는지 지시한다는 것입니다. 체인은 Observable#observeOn(Scheduler) 에 대한 호출이 다른 스케줄러로 만들어질 때까지 Observable#subscribeOn(Scheduler) 에 지정된 스케줄러의 스레드에서 계속 실행됩니다. 이러한 호출이 이루어지면 그 이후의 모든 관찰자(즉, 체인 아래의 후속 작업)는 observeOn 스케줄러에서 가져온 스레드에서 알림을 받습니다.

다음은 이러한 메서드가 작업이 실행되는 위치에 미치는 영향을 보여주는 대리석 다이어그램입니다.

이러한 방법이 작업이 실행되는 위치에 어떻게 영향을 미치는지 보여주는 대리석 다이어그램.

Android 컨텍스트에서 긴 작업의 결과로 UI 작업이 발생해야 하는 경우 해당 작업이 UI 스레드에서 발생하기를 원합니다. 이를 위해 RxAndroid 라이브러리에서 제공하는 스케줄러 중 하나인 AndroidScheduler#mainThread() 를 사용할 수 있습니다.

안드로이드의 RxJava

이제 몇 가지 기본 사항을 알게 되었으므로 Android 애플리케이션에서 RxJava를 통합하는 가장 좋은 방법은 무엇인지 궁금해할 것입니다. 상상할 수 있듯이 RxJava에는 많은 사용 사례가 있지만 이 예에서는 Observable 객체를 네트워크 스택의 일부로 사용하는 한 가지 특정 사례를 살펴보겠습니다.

이 예에서 우리는 GitHub의 API와 상호 작용하기 위해 RxJava와의 빌트인 바인딩이 있는 Square에서 공개한 HTTP 클라이언트인 Retrofit을 살펴볼 것입니다. 특히 GitHub 사용자 이름이 지정된 사용자에 대해 별표 표시된 모든 리포지토리를 표시하는 간단한 앱을 만들 것입니다. 앞으로 나아가고 싶다면 여기에서 소스 코드를 사용할 수 있습니다.

새 Android 프로젝트 만들기

  • 새 Android 프로젝트를 만들고 이름을 GitHubRxJava 로 지정하여 시작합니다.

스크린샷: 새 Android 프로젝트 만들기

  • Target Android Devices 화면에서 Phone 및 Tablet을 선택한 상태로 유지하고 최소 SDK 레벨을 17로 설정합니다. 더 낮거나 더 높은 API 레벨로 자유롭게 설정하지만 이 예에서는 API 레벨 17이면 충분합니다.

스크린샷: 대상 Android 기기 화면

  • 다음 프롬프트에서 빈 활동 을 선택하십시오.

스크린샷: 모바일 화면에 활동 추가

  • 마지막 단계에서 활동 이름을 MainActivity 로 유지하고 레이아웃 파일 activity_main 을 생성합니다.

스크린샷: 활동 화면 사용자 지정

프로젝트 설정

RxJava, RxAndroid 및 Retrofit 라이브러리를 app/build.gradle 에 포함합니다. RxAndroid를 포함하면 암시적으로 RxJava도 포함됩니다. 그러나 RxAndroid에 항상 최신 버전의 RxJava가 포함되어 있지는 않으므로 두 라이브러리를 항상 명시적으로 포함하는 것이 가장 좋습니다. 최신 버전의 RxJava를 명시적으로 포함하면 최신 버전의 사용이 보장됩니다.

 dependencies { compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'io.reactivex:rxandroid:1.2.0' compile 'io.reactivex:rxjava:1.1.8' // ...other dependencies }

데이터 개체 만들기

GitHubRepo 데이터 개체 클래스를 만듭니다. 이 클래스는 GitHub의 리포지토리를 캡슐화합니다(네트워크 응답에는 더 많은 데이터가 포함되어 있지만 우리는 그 중 일부에만 관심이 있습니다).

 public class GitHubRepo { public final int id; public final String name; public final String htmlUrl; public final String description; public final String language; public final int stargazersCount; public GitHubRepo(int id, String name, String htmlUrl, String description, String language, int stargazersCount) { this.id = id; this.name = name; this.htmlUrl = htmlUrl; this.description = description; this.language = language; this.stargazersCount = stargazersCount; } }

개보수 설정

  • GitHubService 인터페이스를 만듭니다. 우리는 이 인터페이스를 Retrofit에 전달할 것이고 Retrofit은 GitHubService 의 구현을 생성할 것입니다.
 public interface GitHubService { @GET("users/{user}/starred") Observable<List<GitHubRepo>> getStarredRepositories(@Path("user") String userName); }
  • GitHubClient 클래스를 만듭니다. 이것은 UI 수준에서 네트워크 호출을 만들기 위해 상호 작용할 개체입니다.

    • Retrofit을 통해 GitHubService 의 구현을 구성할 때 네트워크 호출이 Observable 개체를 반환할 수 있도록 RxJavaCallAdapterFactoryCall 어댑터로 전달해야 합니다.

    • 또한 JSON 개체를 Java 개체로 마샬링하는 방법으로 Gson을 사용할 수 있도록 GsonConverterFactory 를 전달해야 합니다.

 public class GitHubClient { private static final String GITHUB_BASE_URL = "https://api.github.com/"; private static GitHubClient instance; private GitHubService gitHubService; private GitHubClient() { final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); final Retrofit retrofit = new Retrofit.Builder().baseUrl(GITHUB_BASE_URL) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson)) .build(); gitHubService = retrofit.create(GitHubService.class); } public static GitHubClient getInstance() { if (instance == null) { instance = new GitHubClient(); } return instance; } public Observable<List<GitHubRepo>> getStarredRepos(@NonNull String userName) { return gitHubService.getStarredRepositories(userName); } }

레이아웃 설정

다음으로 입력 GitHub 사용자 이름이 제공된 검색된 저장소를 표시하는 간단한 UI를 만듭니다. 다음과 같이 액티비티의 레이아웃인 activity_home.xml 을 생성합니다.

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andro android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ListView android: android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <EditText android: android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="@string/username"/> <Button android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/search"/> </LinearLayout> </LinearLayout>

다음 item_github_repo.xml - GitHub 리포지토리 개체의 ListView 항목 레이아웃을 만듭니다.

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:andro xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="6dp"> <TextView android: android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="24sp" android:text tools:text="Cropper"/> <TextView android: android:layout_width="match_parent" android:layout_height="wrap_content" android:lines="2" android:ellipsize="end" android:textSize="16sp" android:layout_below="@+id/text_repo_name" tools:text="Android widget for cropping and rotating an image."/> <TextView android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/text_repo_description" android:layout_alignParentLeft="true" android:textColor="?attr/colorPrimary" android:textSize="14sp" android:text tools:text="Language: Java"/> <TextView android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/text_repo_description" android:layout_alignParentRight="true" android:textColor="?attr/colorAccent" android:textSize="14sp" android:text tools:text="Stars: 1953"/> </RelativeLayout>

모든 것을 함께 붙이기

GitHubRepo 개체를 ListView 항목에 바인딩하는 역할을 하는 ListAdapter 를 만듭니다. 이 프로세스는 재활용된 View 가 제공되지 않은 경우 item_github_repo.xmlView 로 확장하는 것을 기본적으로 포함합니다. 그렇지 않으면 재활용된 View 가 재사용되어 너무 많은 View 개체가 부풀려지는 것을 방지합니다.

 public class GitHubRepoAdapter extends BaseAdapter { private List<GitHubRepo> gitHubRepos = new ArrayList<>(); @Override public int getCount() { return gitHubRepos.size(); } @Override public GitHubRepo getItem(int position) { if (position < 0 || position >= gitHubRepos.size()) { return null; } else { return gitHubRepos.get(position); } } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { final View view = (convertView != null ? convertView : createView(parent)); final GitHubRepoViewHolder viewHolder = (GitHubRepoViewHolder) view.getTag(); viewHolder.setGitHubRepo(getItem(position)); return view; } public void setGitHubRepos(@Nullable List<GitHubRepo> repos) { if (repos == null) { return; } gitHubRepos.clear(); gitHubRepos.addAll(repos); notifyDataSetChanged(); } private View createView(ViewGroup parent) { final LayoutInflater inflater = LayoutInflater.from(parent.getContext()); final View view = inflater.inflate(R.layout.item_github_repo, parent, false); final GitHubRepoViewHolder viewHolder = new GitHubRepoViewHolder(view); view.setTag(viewHolder); return view; } private static class GitHubRepoViewHolder { private TextView textRepoName; private TextView textRepoDescription; private TextView textLanguage; private TextView textStars; public GitHubRepoViewHolder(View view) { textRepoName = (TextView) view.findViewById(R.id.text_repo_name); textRepoDescription = (TextView) view.findViewById(R.id.text_repo_description); textLanguage = (TextView) view.findViewById(R.id.text_language); textStars = (TextView) view.findViewById(R.id.text_stars); } public void setGitHubRepo(GitHubRepo gitHubRepo) { textRepoName.setText(gitHubRepo.name); textRepoDescription.setText(gitHubRepo.description); textLanguage.setText("Language: " + gitHubRepo.language); textStars.setText("Stars: " + gitHubRepo.stargazersCount); } } }

MainActivity 에서 모든 것을 함께 붙입니다. 이것은 본질적으로 앱을 처음 시작할 때 표시되는 Activity 입니다. 여기에서 사용자에게 GitHub 사용자 이름을 입력하도록 요청하고 마지막으로 해당 사용자 이름으로 별표 표시된 모든 리포지토리를 표시합니다.

 public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private GitHubRepoAdapter adapter = new GitHubRepoAdapter(); private Subscription subscription; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ListView listView = (ListView) findViewById(R.id.list_view_repos); listView.setAdapter(adapter); final EditText editTextUsername = (EditText) findViewById(R.id.edit_text_username); final Button buttonSearch = (Button) findViewById(R.id.button_search); buttonSearch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final String username = editTextUsername.getText().toString(); if (!TextUtils.isEmpty(username)) { getStarredRepos(username); } } }); } @Override protected void onDestroy() { if (subscription != null && !subscription.isUnsubscribed()) { subscription.unsubscribe(); } super.onDestroy(); } private void getStarredRepos(String username) { subscription = GitHubClient.getInstance() .getStarredRepos(username) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<List<GitHubRepo>>() { @Override public void onCompleted() { Log.d(TAG, "In onCompleted()"); } @Override public void onError(Throwable e) { e.printStackTrace(); Log.d(TAG, "In onError()"); } @Override public void onNext(List<GitHubRepo> gitHubRepos) { Log.d(TAG, "In onNext()"); adapter.setGitHubRepos(gitHubRepos); } }); } }

앱 실행

앱을 실행하면 GitHub 사용자 이름을 입력할 수 있는 입력 상자가 있는 화면이 표시되어야 합니다. 그런 다음 검색하면 별표 표시된 모든 리포지토리 목록이 표시됩니다.

별표 표시된 모든 저장소 목록을 보여주는 앱의 스크린샷.

결론

이것이 RxJava에 대한 유용한 소개와 기본 기능에 대한 개요가 되기를 바랍니다. RxJava에는 강력한 개념이 많이 있으며 잘 문서화된 RxJava 위키를 더 깊이 파고들어 이를 탐색할 것을 촉구합니다.

아래 의견란에 질문이나 의견을 자유롭게 남겨주세요. Twitter @arriolachris에서 저를 팔로우할 수도 있습니다. 여기에서 저는 RxJava와 Android에 대한 모든 것에 대해 많은 트윗을 하고 있습니다.

RxJava에 대한 포괄적인 학습 리소스가 필요하면 Leanpub에서 Angus Huang과 함께 작성한 전자책을 확인할 수 있습니다.

관련 항목: Android 개발을 촉진하는 10가지 Kotlin 기능