欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android中通過RxJava進行響應式程序設計的入門指南

 更新時間:2016年06月18日 15:24:09   作者:hi大頭鬼hi  
響應式編程在Android中的運用是非常犀利的,比如在異常處理和調(diào)度器方面,這里我們將從生命周期等方面來講解Android中通過RxJava進行響應式程序設計的入門指南:

錯誤處理

到目前為止,我們都沒怎么介紹onComplete()和onError()函數(shù)。這兩個函數(shù)用來通知訂閱者,被觀察的對象將停止發(fā)送數(shù)據(jù)以及為什么停止(成功的完成或者出錯了)。

下面的代碼展示了怎么使用這兩個函數(shù):

Observable.just("Hello, world!")
  .map(s -> potentialException(s))
  .map(s -> anotherPotentialException(s))
  .subscribe(new Subscriber<String>() {
    @Override
    public void onNext(String s) { System.out.println(s); }

    @Override
    public void onCompleted() { System.out.println("Completed!"); }

    @Override
    public void onError(Throwable e) { System.out.println("Ouch!"); }
  });

代碼中的potentialException() 和 anotherPotentialException()有可能會拋出異常。每一個Observerable對象在終結(jié)的時候都會調(diào)用onCompleted()或者onError()方法,所以Demo中會打印”Completed!”或者”O(jiān)uch!”。

這種模式有以下幾個優(yōu)點:

1.只要有異常發(fā)生onError()一定會被調(diào)用

這極大的簡化了錯誤處理。只需要在一個地方處理錯誤即可以。

2.操作符不需要處理異常

將異常處理交給訂閱者來做,Observerable的操作符調(diào)用鏈中一旦有一個拋出了異常,就會直接執(zhí)行onError()方法。

3.你能夠知道什么時候訂閱者已經(jīng)接收了全部的數(shù)據(jù)。

知道什么時候任務結(jié)束能夠幫助簡化代碼的流程。(雖然有可能Observable對象永遠不會結(jié)束)

我覺得這種錯誤處理方式比傳統(tǒng)的錯誤處理更簡單。傳統(tǒng)的錯誤處理中,通常是在每個回調(diào)中處理錯誤。這不僅導致了重復的代碼,并且意味著每個回調(diào)都必須知道如何處理錯誤,你的回調(diào)代碼將和調(diào)用者緊耦合在一起。

使用RxJava,Observable對象根本不需要知道如何處理錯誤!操作符也不需要處理錯誤狀態(tài)-一旦發(fā)生錯誤,就會跳過當前和后續(xù)的操作符。所有的錯誤處理都交給訂閱者來做。

調(diào)度器

假設你編寫的Android app需要從網(wǎng)絡請求數(shù)據(jù)(感覺這是必備的了,還有單機么?)。網(wǎng)絡請求需要花費較長的時間,因此你打算在另外一個線程中加載數(shù)據(jù)。那么問題來了!

編寫多線程的Android應用程序是很難的,因為你必須確保代碼在正確的線程中運行,否則的話可能會導致app崩潰。最常見的就是在非主線程更新UI。

使用RxJava,你可以使用subscribeOn()指定觀察者代碼運行的線程,使用observerOn()指定訂閱者運行的線程:

myObservableServices.retrieveImage(url)
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(bitmap -> myImageView.setImageBitmap(bitmap));

是不是很簡單?任何在我的Subscriber前面執(zhí)行的代碼都是在I/O線程中運行。最后,操作view的代碼在主線程中運行.

最棒的是我可以把subscribeOn()和observerOn()添加到任何Observable對象上。這兩個也是操作符!。我不需要關心Observable對象以及它上面有哪些操作符。僅僅運用這兩個操作符就可以實現(xiàn)在不同的線程中調(diào)度。

如果使用AsyncTask或者其他類似的,我將不得不仔細設計我的代碼,找出需要并發(fā)執(zhí)行的部分。使用RxJava,我可以保持代碼不變,僅僅在需要并發(fā)的時候調(diào)用這兩個操作符就可以。

訂閱(Subscriptions)

當調(diào)用Observable.subscribe(),會返回一個Subscription對象。這個對象代表了被觀察者和訂閱者之間的聯(lián)系。

ubscription subscription = Observable.just("Hello, World!")
  .subscribe(s -> System.out.println(s));

你可以在后面使用這個Subscription對象來操作被觀察者和訂閱者之間的聯(lián)系.

subscription.unsubscribe();
System.out.println("Unsubscribed=" + subscription.isUnsubscribed());
// Outputs "Unsubscribed=true"

RxJava的另外一個好處就是它處理unsubscribing的時候,會停止整個調(diào)用鏈。如果你使用了一串很復雜的操作符,調(diào)用unsubscribe將會在他當前執(zhí)行的地方終止。不需要做任何額外的工作!

RxAndroid

RxAndroid是RxJava的一個針對Android平臺的擴展。它包含了一些能夠簡化Android開發(fā)的工具。

首先,AndroidSchedulers提供了針對Android的線程系統(tǒng)的調(diào)度器。需要在UI線程中運行某些代碼?很簡單,只需要使用AndroidSchedulers.mainThread():

retrofitService.getImage(url)
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(bitmap -> myImageView.setImageBitmap(bitmap));

如果你已經(jīng)創(chuàng)建了自己的Handler,你可以使用HandlerThreadScheduler1將一個調(diào)度器鏈接到你的handler上。

接著要介紹的就是AndroidObservable,它提供了跟多的功能來配合Android的生命周期。bindActivity()和bindFragment()方法默認使用AndroidSchedulers.mainThread()來執(zhí)行觀察者代碼,這兩個方法會在Activity或者Fragment結(jié)束的時候通知被觀察者停止發(fā)出新的消息。

AndroidObservable.bindActivity(this, retrofitService.getImage(url))
  .subscribeOn(Schedulers.io())
  .subscribe(bitmap -> myImageView.setImageBitmap(bitmap);

我自己也很喜歡AndroidObservable.fromBroadcast()方法,它允許你創(chuàng)建一個類似BroadcastReceiver的Observable對象。下面的例子展示了如何在網(wǎng)絡變化的時候被通知到:

IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
AndroidObservable.fromBroadcast(context, filter)
  .subscribe(intent -> handleConnectivityChange(intent));

最后要介紹的是ViewObservable,使用它可以給View添加了一些綁定。如果你想在每次點擊view的時候都收到一個事件,可以使用ViewObservable.clicks(),或者你想監(jiān)聽TextView的內(nèi)容變化,可以使用ViewObservable.text()。

ViewObservable.clicks(mCardNameEditText, false)
  .subscribe(view -> handleClick(view));

Retrofit

大名鼎鼎的Retrofit庫內(nèi)置了對RxJava的支持(官方下載頁http://square.github.io/retrofit/#download)。通常調(diào)用發(fā)可以通過使用一個Callback對象來獲取異步的結(jié)果:

@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);

使用RxJava,你可以直接返回一個Observable對象。

@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);

現(xiàn)在你可以隨意使用Observable對象了。你不僅可以獲取數(shù)據(jù),還可以進行變換。
Retrofit對Observable的支持使得它可以很簡單的將多個REST請求結(jié)合起來。比如我們有一個請求是獲取照片的,還有一個請求是獲取元數(shù)據(jù)的,我們就可以將這兩個請求并發(fā)的發(fā)出,并且等待兩個結(jié)果都返回之后再做處理:

Observable.zip(
  service.getUserPhoto(id),
  service.getPhotoMetadata(id),
  (photo, metadata) -> createPhotoWithData(photo, metadata))
  .subscribe(photoWithData -> showPhoto(photoWithData));

在第二篇里我展示過一個類似的例子(使用flatMap())。這里我只是想展示以下使用RxJava+Retrofit可以多么簡單地組合多個REST請求。

遺留代碼,運行極慢的代碼

Retrofit可以返回Observable對象,但是如果你使用的別的庫并不支持這樣怎么辦?或者說一個內(nèi)部的內(nèi)碼,你想把他們轉(zhuǎn)換成Observable的?有什么簡單的辦法沒?

絕大多數(shù)時候Observable.just() 和 Observable.from() 能夠幫助你從遺留代碼中創(chuàng)建 Observable 對象:

private Object oldMethod() { ... }

public Observable<Object> newMethod() {
  return Observable.just(oldMethod());
}

上面的例子中如果oldMethod()足夠快是沒有什么問題的,但是如果很慢呢?調(diào)用oldMethod()將會阻塞住他所在的線程。
為了解決這個問題,可以參考我一直使用的方法–使用defer()來包裝緩慢的代碼:

private Object slowBlockingMethod() { ... }

public Observable<Object> newMethod() {
  return Observable.defer(() -> Observable.just(slowBlockingMethod()));
}

現(xiàn)在,newMethod()的調(diào)用不會阻塞了,除非你訂閱返回的observable對象。

生命周期

我把最難的不分留在了最后。如何處理Activity的生命周期?主要就是兩個問題:
1.在configuration改變(比如轉(zhuǎn)屏)之后繼續(xù)之前的Subscription。

比如你使用Retrofit發(fā)出了一個REST請求,接著想在listview中展示結(jié)果。如果在網(wǎng)絡請求的時候用戶旋轉(zhuǎn)了屏幕怎么辦?你當然想繼續(xù)剛才的請求,但是怎么搞?

2.Observable持有Context導致的內(nèi)存泄露

這個問題是因為創(chuàng)建subscription的時候,以某種方式持有了context的引用,尤其是當你和view交互的時候,這太容易發(fā)生!如果Observable沒有及時結(jié)束,內(nèi)存占用就會越來越大。
不幸的是,沒有銀彈來解決這兩個問題,但是這里有一些指導方案你可以參考。

第一個問題的解決方案就是使用RxJava內(nèi)置的緩存機制,這樣你就可以對同一個Observable對象執(zhí)行unsubscribe/resubscribe,卻不用重復運行得到Observable的代碼。cache() (或者 replay())會繼續(xù)執(zhí)行網(wǎng)絡請求(甚至你調(diào)用了unsubscribe也不會停止)。這就是說你可以在Activity重新創(chuàng)建的時候從cache()的返回值中創(chuàng)建一個新的Observable對象。

Observable<Photo> request = service.getUserPhoto(id).cache();
Subscription sub = request.subscribe(photo -> handleUserPhoto(photo));

// ...When the Activity is being recreated...
sub.unsubscribe();

// ...Once the Activity is recreated...
request.subscribe(photo -> handleUserPhoto(photo));

注意,兩次sub是使用的同一個緩存的請求。當然在哪里去存儲請求的結(jié)果還是要你自己來做,和所有其他的生命周期相關的解決方案一延虎,必須在生命周期外的某個地方存儲。(retained fragment或者單例等等)。

第二個問題的解決方案就是在生命周期的某個時刻取消訂閱。一個很常見的模式就是使用CompositeSubscription來持有所有的Subscriptions,然后在onDestroy()或者onDestroyView()里取消所有的訂閱。

private CompositeSubscription mCompositeSubscription
  = new CompositeSubscription();

private void doSomething() {
  mCompositeSubscription.add(
    AndroidObservable.bindActivity(this, Observable.just("Hello, World!"))
    .subscribe(s -> System.out.println(s)));
}

@Override
protected void onDestroy() {
  super.onDestroy();

  mCompositeSubscription.unsubscribe();
}

你可以在Activity/Fragment的基類里創(chuàng)建一個CompositeSubscription對象,在子類中使用它。

注意! 一旦你調(diào)用了 CompositeSubscription.unsubscribe(),這個CompositeSubscription對象就不可用了, 如果你還想使用CompositeSubscription,就必須在創(chuàng)建一個新的對象了。

相關文章

  • Android編程實現(xiàn)獲取新浪天氣預報數(shù)據(jù)的方法

    Android編程實現(xiàn)獲取新浪天氣預報數(shù)據(jù)的方法

    這篇文章主要介紹了Android編程實現(xiàn)獲取新浪天氣預報數(shù)據(jù)的方法,涉及Android基于新浪接口的調(diào)用及數(shù)據(jù)處理技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • Android實現(xiàn)自定義標題欄的方法

    Android實現(xiàn)自定義標題欄的方法

    這篇文章主要介紹了Android實現(xiàn)自定義標題欄的方法,需要的朋友可以參考下
    2015-12-12
  • Android組件化、插件化詳細講解

    Android組件化、插件化詳細講解

    這篇文章主要介紹了Android組件化、插件化詳細講解,這些單獨?次封裝的功能模塊apk,就稱作插件,文章圍繞主題展開詳細的內(nèi)容介紹,需要的朋友可以參考一下
    2022-07-07
  • 詳解Android App中ViewPager使用PagerAdapter的方法

    詳解Android App中ViewPager使用PagerAdapter的方法

    這篇文章主要介紹了詳解Android App中ViewPager使用PagerAdapter的方法,同時附帶了一個ViewPager的PagerAdapter不能更新數(shù)據(jù)的問題解決方法,需要的朋友可以參考下
    2016-03-03
  • Android利用ContentProvider初始化組件的踩坑記錄

    Android利用ContentProvider初始化組件的踩坑記錄

    做Android SDK開發(fā)的時候,一般我們會將初始化的方法封裝,然后讓調(diào)用SDK的開發(fā)者在Application的onCreate方法中進行初始化,下面這篇文章主要給大家介紹了關于Android利用ContentProvider初始化組件的踩坑記錄,需要的朋友可以參考下
    2022-04-04
  • Android實現(xiàn)兩圓點之間來回移動加載進度

    Android實現(xiàn)兩圓點之間來回移動加載進度

    這篇文章主要為大家詳細介紹了Android實現(xiàn)兩圓點之間來回移動加載進度,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • Android實現(xiàn)帶列表的地圖POI周邊搜索功能

    Android實現(xiàn)帶列表的地圖POI周邊搜索功能

    這篇文章主要為大家詳細介紹了Android實現(xiàn)帶列表的地圖POI周邊搜索功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Android使用Intent傳大數(shù)據(jù)簡單實現(xiàn)詳解

    Android使用Intent傳大數(shù)據(jù)簡單實現(xiàn)詳解

    這篇文章主要為大家介紹了Android使用Intent傳大數(shù)據(jù)簡單實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • Android Vitamio和ExoPlayer兩種播放器優(yōu)劣分析

    Android Vitamio和ExoPlayer兩種播放器優(yōu)劣分析

    Vitamio和ExoPlayer都是用于安卓平臺的視頻播放器庫,它們各有優(yōu)缺點,具體使用哪一個,需要根據(jù)你的實際需求、開發(fā)經(jīng)驗、項目規(guī)模等多個因素綜合考慮
    2023-04-04
  • Android使用硬件加速的方式

    Android使用硬件加速的方式

    硬件加速是指利用設備的硬件資源來加速圖形渲染和圖像處理等操作,以提高應用程序的性能和用戶體驗,Android使用硬件加速的目的是為了提高圖形渲染的性能和效果,本文給大家詳細介紹了Android如何使用硬件加速,需要的朋友可以參考下
    2023-10-10

最新評論