Retrofit2+RXJava1(初識篇)

一:觀察者模式基本實現

1. 創建觀察者Subscriber

	Subscriber<String> subscriber = new Subscriber<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }
    @Override
    public void onCompleted() {
        Log.d(tag, "Completed!");
    }
    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!");
    }
};

2. 創建被觀察者Observable ,observable是被觀察者,subscribe是訂閱者,onsbuscribe是訂閱的接口,裏面有個call方法需要實現

Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello");
        subscriber.onNext("fyc");
        subscriber.onCompleted();
    }
});

3. 完成訂閱

observable.subscribe(subscriber);

//該方法的源碼是:
public Subscription subscribe(Subscriber subscriber) {
    subscriber.onStart();
    onSubscribe.call(subscriber);   //由此可見觀察者不是在創建的時候就發送請求的,而是在訂閱的時候才call的 
    return subscriber;   //將傳入的 Subscriber 作爲 Subscription 返回。這是爲了方便 unsubscribe().
                         //另外:public abstract class Subscriber<T> implements Observer<T>, Subscription {}所以這個類可以強轉爲接口
}

4. 快捷創建事件隊列

	1> just(T...): 將傳入的參數依次發送出來。
	  Observable observable = Observable.just("Hello", "Hi", "Aloha")
	  									.subscribe(subscriber);
	  // 將會依次調用:
	  // onNext("Hello");
	  // onNext("Hi");
	  // onNext("Aloha");
	  // onCompleted();
	2> String[] words = {"Hello", "Hi", "Aloha"};
	  Observable observable = Observable.from(words)
	              .subscribe(subscriber);
	  // 將會依次調用:
	  // onNext("Hello");
	  // onNext("Hi");
	  // onNext("Aloha");
	  // onCompleted();

5. 除了 subscribe(Observer) 和 subscribe(Subscriber) , subscribe() 還支持不完整定義的回調

Action1<String> onNextAction = new Action1<String>() {
    // onNext()
    @Override
    public void call(String s) {
        Log.d(tag, s);
    }
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
    // onError()
    @Override
    public void call(Throwable throwable) {
        // Error handling
    }
};
Action0 onCompletedAction = new Action0() {
    // onCompleted()
    @Override
    public void call() {
        Log.d(tag, "completed");
    }
};

簡單解釋一下這段代碼中出現的 Action1 和 Action0。 Action0 是 RxJava 的一個接口,它只有一個方法 call(),這個方法是無參無返回值的;
由於 onCompleted() 方法也是無參無返回值的,因此 Action0 可以被當成一個包裝對象,將 onCompleted() 的內容打包起來將自己作爲一個參數傳入 subscribe() 以實現不完整定義的回調。
這樣其實也可以看做將 onCompleted() 方法作爲參數傳進了 subscribe(),相當於其他某些語言中的『閉包』。 Action1 也是一個接口,它同樣只有一個方法 call(T param),這個方法也無返回值,但有一個參數;
與 Action0 同理,由於 onNext(T obj) 和 onError(Throwable error) 也是單參數無返回值的,
因此 Action1 可以將 onNext(obj) 和 onError(error) 打包起來傳入 subscribe() 以實現不完整定義的回調。事實上,雖然 Action0 和 Action1 在 API 中使用最廣泛,但 RxJava 是提供了多個 ActionX 形式的接口 (例如 Action2, Action3) 的,它們可以被用以包裝不同的無返回值的方法。


注:正如前面所提到的,Observer 和 Subscriber 具有相同的角色,而且 Observer 在 subscribe() 過程中最終會被轉換成 Subscriber 對象,因此,從這裏開始,後面的描述我將用 Subscriber 來代替 Observer ,這樣更加嚴謹。

6. demo示例

int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
    @Override
    public void call(Subscriber<? super Drawable> subscriber) {
        Drawable drawable = getTheme().getDrawable(drawableRes));
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
})
.subscribeOn(Schedulers.io()) // 指定 subscribe() 發生在 IO 線程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調發生在主線程
.subscribe(new Observer<Drawable>() {
    @Override
    public void onNext(Drawable drawable) {
        imageView.setImageDrawable(drawable);
    }
    @Override
    public void onCompleted() {
    }

    @Override
    public void onError(Throwable e) {
	 Toast.makeText(activity, "Error!",  Toast.LENGTH_SHORT).show();
    }
});

二:時間調度,實現觀察者模式的異步調度(scheduler:調度器)

1. 調度器分爲如下四種

Schedulers.immediate(): 直接在當前線程運行,相當於不指定線程。這是默認的 Scheduler。
Schedulers.newThread(): 總是啓用新線程,並在新線程執行操作。
Schedulers.io(): I/O 操作(讀寫文件、讀寫數據庫、網絡信息交互等)所使用的 Scheduler。行爲模式和 newThread() 差不多,區別在於 io() 的內部實現是是用一個無數量上限的線程池,可以重用空閒的線程,因此多數情況下 io() 比 newThread() 更有效率。不要把計算工作放在 io() 中,可以避免創建不必要的線程。
Schedulers.computation(): 計算所使用的 Scheduler。這個計算指的是 CPU 密集型計算,即不會被 I/O 等操作限制性能的操作,例如圖形的計算。這個 Scheduler 使用的固定的線程池,大小爲 CPU 核數。不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時間會浪費 CPU。
另外, Android 還有一個專用的 AndroidSchedulers.mainThread(),它指定的操作將在 Android 主線程運行。

2. demo示例

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 發生在 IO 線程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調發生在主線程,既會在主線程打印1234
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

三:完成對事件序列的變換(如將string轉換爲bitmap),map與flatMap

1> 獲取所有學生的名字

	Student[] students = ...;
	Subscriber<String> subscriber = new Subscriber<String>() {
	    @Override
	    public void onNext(String name) {
	        Log.d(tag, name);
	    }
	    ...
	};
	Observable.from(students)
	    .map(new Func1<Student, String>() {
	        @Override
	        public String call(Student student) {
	            return student.getName();
	        }
	    })
	    .subscribe(subscriber);
注意: FuncX 和 ActionX 的區別在 FuncX 包裝的是有返回值的方法。
總結:map可以很容易的實現將一種對象轉換爲另一種對象,是一對一的關係,而flatmap是一對多的關係。

2> 獲取所有學生的所有課程

	Student[] students = ...;
	Subscriber<Course> subscriber = new Subscriber<Course>() {
	    @Override
	    public void onNext(Course course) {
	        Log.d(tag, course.getName());
	    }
	    ...
	};
	Observable.from(students)
	    .flatMap(new Func1<Student, Observable<Course>>() {
	        @Override
	        public Observable<Course> call(Student student) {
	            return Observable.from(student.getCourses());
	        }
	    })
	    .subscribe(subscriber);

	//總結:將所有的事件封在observable中,鋪平後統一分發給訂閱者

四:防抖動

在每次事件觸發後的一定時間間隔內丟棄新的事件。常用作去抖動過濾,例如按鈕的點擊監聽器:
RxView.clickEvents(button) .throttleFirst(500, TimeUnit.MILLISECONDS) // RxBinding 代碼,設置防抖間隔爲 500ms .subscribe(subscriber); 媽媽再也不怕我的用戶手抖點開兩個重複的界面啦。

五:rxjava與retrofit適用場合

  • 1> 請求完數據後,需要做進一步的耗時操作,比如從數據庫拿東西時:
	a: Callback方式:
	
		getUser(userId, new Callback<User>() {
	    @Override
	    public void success(User user) {
	        new Thread() {
	            @Override
	            public void run() {
	                processUser(user); // 嘗試修正 User 數據
	                runOnUiThread(new Runnable() { // 切回 UI 線程
	                    @Override
	                    public void run() {
	                        userView.setUser(user);
	                    }
	                });
	            }).start();
	    }
	    @Override
	    public void failure(RetrofitError error) {
	        // Error handling
	        ...
	    }
	};
	b: RxJava 的形式

		getUser(userId)
	    .doOnNext(new Action1<User>() {
	        @Override
	        public void call(User user) {
	            processUser(user);
	        })
	    .observeOn(AndroidSchedulers.mainThread())
	    .subscribe(new Observer<User>() {
	        @Override
	        public void onNext(User user) {
	            userView.setUser(user);
	        }
	        @Override
	        public void onCompleted() {
	        }
	        @Override
	        public void onError(Throwable error) {
	            // Error handling
	            ...
	        }
	    });
//可以看出rxjava對後臺進一步耗時操作有專門的處理,doOnNext直接處理
  • 2> 兩次網絡請求需要嵌套時:
	a: Callback方式:
		@GET("/token")
		public void getToken(Callback<String> callback);

		@GET("/user")
		public void getUser(@Query("token") String token, @Query("userId") String userId, Callback<User> callback);

		...

		getToken(new Callback<String>() {
		    @Override
		    public void success(String token) {
		        getUser(token, userId, new Callback<User>() {
		            @Override
		            public void success(User user) {
		                userView.setUser(user);
		            }

		            @Override
		            public void failure(RetrofitError error) {
		                // Error handling
		                ...
		            }
		        };
		    }

		    @Override
		    public void failure(RetrofitError error) {
		        // Error handling
		        ...
		    }
		});
	b: RxJava 的形式
		getToken()
	    .flatMap(new Func1<String, Observable<User>>() {
	        @Override
	        public Observable<User> onNext(String token) {
	            return getUser(token, userId);
	        })
	    .observeOn(AndroidSchedulers.mainThread())
	    .subscribe(new Observer<User>() {
	        @Override
	        public void onNext(User user) {
	            userView.setUser(user);
	        }

	        @Override
	        public void onCompleted() {
	        }

	        @Override
	        public void onError(Throwable error) {
	            // Error handling
	            ...
	        }
	    });
//可以看出rxjava對於兩次網絡請求不需要兩次的callback,一個flatMap搞定

最後,感謝文章:http://gank.io/post/560e15be2dca930e00da1083

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章