钢铁侠手机java游戏_android-tech-frontier
當(dāng)鋼鐵俠反應(yīng)更靈敏-RxJava
本系列的這個(gè)部分主要是講一些函數(shù)式技巧能給我們的項(xiàng)目帶來的好處。
ReactiveX 中的 RxJava 是一個(gè)可以幫助我們輕松處理不同運(yùn)行環(huán)境下的后臺(tái)線程或UI線程任務(wù)的框架。這在 Android 上一直是我們所有人的噩夢。
這篇文章主要會(huì)談?wù)勂渲?RxJava)的一些 operators 如何能在常見開發(fā)任務(wù)中為我們節(jié)省時(shí)間,Reactive Extensions 提供了很多種類的 operators 來讓我們用的更方便。
像以前一樣,大部分代碼和片段都已經(jīng)上傳到了 Github, 請隨意評(píng)論、提 issue 或吐槽!
在本系列第一部分中我們介紹了 Dagger 2,現(xiàn)在我們更進(jìn)一步會(huì)看到如何降低各層代碼邏輯之間的耦合、增加可擴(kuò)展性。
RetroLambda
有時(shí),在 Java 開發(fā)的大型應(yīng)用程序中,或 Android 這樣的大型框架中,使用 Java 8 中的 Lambda 表達(dá)式這類特性是非常困難或是幾乎不可能的(Android中)。
Retrolambda 就是來解決這個(gè)問題的,它會(huì)把 Java 8 的字節(jié)碼翻譯成低版本 Java 像v7甚至v5、v6的字節(jié)碼,這樣可以讓我們在這些低版本中使用到 Lambda 表達(dá)式的特性。
Retrolambda 可以通過 Gradle 或 Maven 的方式來使用,我選擇 Gradle 是因?yàn)?Android Studio 對其支持的很好。要使用它你只需要將 [Retrolambda](https://github.com/orfjackal/retrolambda) 插件加到項(xiàng)目根目錄的 build.gradle, 同時(shí)在 module 的 build 腳本中應(yīng)用它,再設(shè)置 Android Studio 的語言級(jí)別到 1.8,這就完成了。
build.gradle (root)
dependencies {
classpath 'me.tatarka:gradle-retrolambda:3.1.0'
}
{your module}/build.gradle
apply plugin: 'me.tatarka.retrolambda'
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
Retrolambda可以讓你少寫很多重復(fù)的代碼,同時(shí)理順我們的代碼讓它有更好的可讀性。在 Dan Lew給出的這個(gè)例子中,你可以感受到它所帶來的不同。
沒有 Retrolambda
Observable.just("Hello, world!")
.subscribe(new Action1() {
@Override
public void call(String s) {
System.out.println(s);
}
});
有 Retrolambda
Observable.just("Hello, world!") .subscribe(
s -> System.out.println(s)
);
在我們的 Avengers 示例中
mCharacterSubscription = mGetCharacterInformationUsecase
.execute().subscribe(
character -> onAvengerReceived(character),
error -> manageError(error)
);
mComicsSubscription = mGetCharacterComicsUsecase
.execute().subscribe(
comics -> Observable.from(comics).subscribe(
comic -> onComicReceived(comic)),
error -> manageError(throwable)
);
ReactiveX
ReactiveX 是一個(gè)開源項(xiàng)目的集合,它們所遵循的主要原則都是 Observer 模式、Iterator 模式以及函數(shù)式編程。
ReactiveX 同時(shí)也提供了可用于異步編程的API,事實(shí)上使用這些框架來實(shí)現(xiàn)異步任務(wù)非常簡單。
ReactiveX 的異步客戶端用法
在使用 ReactiveX 時(shí)最棒的是你可以創(chuàng)建一個(gè)完全異步的API或客戶端,在實(shí)現(xiàn)具體邏輯的時(shí)候再?zèng)Q定是把代碼寫成異步的、放到線程池中的一個(gè)獨(dú)立線程執(zhí)行、還是同步來執(zhí)行。
因此我們可以得到一個(gè)觀察者模式的API而不是一個(gè)阻塞調(diào)用的API。
public interface Usecase {
Observable execute();
}
public interface Repository {
Observable getCharacter (final int characterId);
Observable> getCharacterComics (final int characterId);
}
RxJava是什么
RxJava 是一個(gè)由 Netflix 開發(fā)的 Reactive Extensions的(Java版)實(shí)現(xiàn)。其他還有大量主流編程語言的實(shí)現(xiàn),包括 Javascript, Python, Ruby, Go 等等。
Observables 和 Observers
一個(gè) Observable 可以輸出一個(gè)或一系列的 objects,這些 objects 會(huì)被訂閱到這個(gè) Observable 的 Observer 所處理或接收。
把一個(gè) Observer 注冊到一個(gè) Observable 上是很必要的,如果不這么做的話 Observable 什么都不會(huì)輸出。當(dāng) Observer 注冊之后,一個(gè) Subscription 類型的實(shí)例會(huì)創(chuàng)建,它可以用來取消對 Observable 的訂閱,這通常在 Activities 和 Fragments 的 onStop 或 onPause 方法中非常有用,例如:
mCharacterSubscription = mGetCharacterInformationUsecase
.execute().subscribe( ... );
@Override
public void onStop() {
if (!mCharacterSubscription.isUnsubscribed())
mCharacterSubscription.unsubscribe();
if (!mComicsSubscription.isUnsubscribed())
mComicsSubscription.unsubscribe();
}
無論何時(shí) Observer 訂閱 Observable 的消息,它都需要考慮處理3個(gè)方法:
onNext (T) 方法用來接收 Observable 發(fā)出的 objects.
onError (Exception),這個(gè)方法會(huì)在內(nèi)部拋出異常的時(shí)候調(diào)用。
onCompleted(),這個(gè)方法會(huì)在 Observable 停止釋放 objects 的時(shí)候調(diào)用。
我喜歡這張圖 :)
組件間通信
讓我們來看看如何使用 GetCharacterInformationUsecase 這個(gè)用例,所有的用例都實(shí)現(xiàn)了 Usecase 接口。
public interface Usecase {
Observable execute();
}
這個(gè)例子被調(diào)用的時(shí)候會(huì)返回一個(gè) Observable 類型的實(shí)例,它可以輕松的和其他的 observables 和 operators 組合成鏈?zhǔn)浇Y(jié)構(gòu),我們很快將會(huì)看到這些 operators 的強(qiáng)大威力。
當(dāng)我們調(diào)用 GetCharacterInformationUsecase 的時(shí)候請求我們的倉庫產(chǎn)生一個(gè)對應(yīng)類型的數(shù)據(jù)源:
@Override
public Observable execute() {
return mRepository.getCharacter(mCharacterId);
// .awesomeRxStuff();
}
AvengerDetailPresenter 這個(gè) presenter 將會(huì)成為我們這個(gè)用例的 Observer,它將會(huì)訂閱這個(gè) Observable 發(fā)出的所有事件,這個(gè)操作可以通過調(diào)用 subscribe 方法來完成,這樣就把 Observer 和 Observable 關(guān)聯(lián)在一起了。
實(shí)現(xiàn) onNext 和 onError 方法可以來處理操作結(jié)果。onCompleted 方法并沒有實(shí)現(xiàn),因?yàn)樵谶@個(gè)例子中不需要。
mCharacterSubscription = mGetCharacterInformationUsecase
.execute().subscribe(
character -> onAvengerReceived(character),
error -> manageError(error));
Retrofit 和 RxJava
Square 出品了 Retrofit,RxJava 支持其中的 rx.Observable 方法,這樣網(wǎng)絡(luò)請求的結(jié)果就可以通過 Observer 的方式來訂閱、修改或通過 operators 加工。
你一定得十分清楚在什么地方來調(diào)用它,Retrofit 的請求會(huì)在 Observable 所在線程上來執(zhí)行,因此當(dāng)你在 UI 線程(Activity 或 Fragment 中)來調(diào)用的話就會(huì)報(bào)錯(cuò)。接下來我們講講 Schedulers!
Schedulers
Schedulers 可以讓你在多線程中使用 operators 和 Observables。它可以被用在不同的線程、一個(gè) 線程 Executor 或是預(yù)設(shè)的 [Schedulers](http://reactivex.io/documentation/scheduler.html) 中。例如,對于輸入或輸出這類操作會(huì)在 Schedulers.io () 來執(zhí)行。
RxAndroid 是由 Jake Wharton 和 Matthias K?ppler 開發(fā)的一些 Android 下專用的 RxJava 的工具,其中包括一些用來處理 Android 平臺(tái)下多進(jìn)程調(diào)用的 Schedulers。
它也提供了使用 Android 的 Handler 來處理并發(fā)的方式。
@Override
public Observable execute() {
return mRepository.getCharacter(mCharacterId)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
這個(gè)例子演示了 Rx 提供的處理 Android 中多進(jìn)程調(diào)用的方式,這真是非常的炫酷 :D
Operators
ReactiveX 最厲害的要數(shù)它的 operators 了,它們可以用來操作、變換、合并 Observables 輸出的 objecs。
我們來看看一個(gè)漫畫列表的例子,漫畫都有一個(gè)特定的出版年份,我們想要展示特定年份出版的漫畫,這時(shí) ReactiveX 就能大顯身手了!
這個(gè)過濾過程是通過 filter 這個(gè) operator 來完成的,它可以作為漫畫的一個(gè)約束條件來加以判斷。在這個(gè)過程中,詢問用戶要過濾出哪一年,然后使用這個(gè)年份來判定一個(gè)漫畫是否允許被展示。
public Observable filterByYear(String year) {
if (mComics != null) {
return Observable.from(mComics).filter(
comic -> {
for (ComicDate comicDate : comic.getDates())
if (comicDate.getDate().startsWith(year))
return true;
return false;
});
}
return null;
}
異常處理
另一個(gè)很好的 Rx 的 operators 能幫我們節(jié)省時(shí)間提升效率的例子是異常處理的 operators。
設(shè)想一個(gè)用戶要請求網(wǎng)絡(luò),但是在網(wǎng)絡(luò)通道上發(fā)生了一些偶然因素,網(wǎng)絡(luò)連接在這種情況下受到了影響。
當(dāng)我們接收到了 Retrofit 拋出的 SocketTimeoutException 異常時(shí),我們可以利用 retry 這個(gè) operator 來處理。
retry 可以接收一個(gè)判定條件,就像之前我們在 filter 中所做的一樣,如果返回 true,那么 Rx 就會(huì)神奇的再次調(diào)用 Observable 重新執(zhí)行 Retrofit 的網(wǎng)絡(luò)請求。
如果最多拋出了3次 SocketTimeoutExceptions 異常,程序會(huì)繼續(xù)執(zhí)行后續(xù)的 onError 來處理異常。
@Override
public Observable> getCharacterComics(int characterId) {
final String comicsFormat = "comic";
final String comicsType = "comic";
return mMarvelApi.getCharacterComics(
characterId, comicsFormat, comicsType)
.retry((attemps, error) ->
error instanceof SocketTimeoutException &&
attemps < MAX_ATTEMPS);
}
一些參考資料
總結(jié)
以上是生活随笔為你收集整理的钢铁侠手机java游戏_android-tech-frontier的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python + selenium 爬取
- 下一篇: STM32F407霸天虎HAL库学习笔记