前言:對Rxjava、Rxandroid不瞭解的同學可以先看看
RxJava 和 RxAndroid
RxJava 和 RxAndroid 二(操作符的使用)
RxJava使我們很方便的使用鏈式程式設計,程式碼看起來既簡潔又優雅。但是RxJava使用起來也是有副作用的,使用越來越多的訂閱,記憶體開銷也會變得很大,稍不留神就會出現記憶體溢位的情況,這篇文章就是介紹Rxjava使用過程中應該注意的事項。
1、取消訂閱 subscription.unsubscribe()
;
package lib.com.myapplication;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import rx.Observable;
import rx.Subscription;
import rx.functions.Action1;
public class MainActivity extends AppCompatActivity {
Subscription subscription ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
subscription = Observable.just( "123").subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println( "tt--" + s );
}
}) ;
}
@Override
protected void onDestroy() {
super.onDestroy();
//取消訂閱
if ( subscription != null ){
subscription.unsubscribe();
}
}
}
2、執行緒排程
-
Scheduler排程器,相當於執行緒控制器
-
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。 -
還有RxAndroid裡面專門提供了
AndroidSchedulers.mainThread()
,它指定的操作將在 Android 主執行緒執行。
-
-
常見的場景:為了不阻塞UI,在子執行緒載入資料,在主線執行緒顯示資料
Observable.just( "1" , "2" , "3" ) .subscribeOn(Schedulers.io()) //指定 subscribe() 發生在 IO 執行緒 .observeOn( AndroidSchedulers.mainThread() ) //指定 Subscriber 的回撥發生在主執行緒 .subscribe(new Action1<String>() { @Override public void call(String s) { textView.setText( s ); } }) ;
上面這段程式碼,資料"1"、"2"、"3"將在io執行緒中發出,在android主執行緒中接收資料。這種【後臺獲取資料,前臺顯示資料】模式適用於大多數的程式策略。
-
Scheduler 自由多次切換執行緒。恩,這個更為牛逼
Observable.just(1, 2, 3, 4) // IO 執行緒,由 subscribeOn() 指定 .subscribeOn(Schedulers.io()) .observeOn(Schedulers.newThread()) .map(mapOperator) // 新執行緒,由 observeOn() 指定 .observeOn(Schedulers.io()) .map(mapOperator2) // IO 執行緒,由 observeOn() 指定 .observeOn(AndroidSchedulers.mainThread) .subscribe(subscriber); // Android 主執行緒,由 observeOn() 指定
從上面的程式碼可以看出
-
observeOn()
可以呼叫多次來切換執行緒,observeOn 決定他下面的方法執行時所在的執行緒。 -
subscribeOn()
用來確定資料發射所在的執行緒,位置放在哪裡都可以,但它是隻能呼叫一次的。
-
-
上面介紹了兩種控制Rxjava生命週期的方式,第一種:取消訂閱 ;第二種:執行緒切換 。這兩種方式都能有效的解決android記憶體的使用問題,但是在實際的專案中會出現很多訂閱關係,那麼取消訂閱的程式碼也就越來越多。造成了專案很難維護。所以我們必須尋找其他可靠簡單可行的方式,也就是下面要介紹的。
3、rxlifecycle 框架的使用
-
github地址: https://github.com/trello/RxLifecycle
-
在android studio 裡面新增引用
compile 'com.trello:rxlifecycle-components:0.6.1'
-
讓你的activity繼承
RxActivity
,RxAppCompatActivity
,RxFragmentActivity
讓你的fragment繼承RxFragment
,RxDialogFragment
;下面的程式碼就以RxAppCompatActivity
舉例 -
bindToLifecycle
方法
在子類使用Observable中的compose操作符,呼叫,完成Observable釋出的事件和當前的元件繫結,實現生命週期同步。從而實現當前元件生命週期結束時,自動取消對Observable訂閱。public class MainActivity extends RxAppCompatActivity { TextView textView ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textView); //迴圈傳送數字 Observable.interval(0, 1, TimeUnit.SECONDS) .subscribeOn( Schedulers.io()) .compose(this.<Long>bindToLifecycle()) //這個訂閱關係跟Activity繫結,Observable 和activity生命週期同步 .observeOn( AndroidSchedulers.mainThread()) .subscribe(new Action1<Long>() { @Override public void call(Long aLong) { System.out.println("lifecycle--" + aLong); textView.setText( "" + aLong ); } }); } }
上面的程式碼是Observable迴圈的傳送數字,並且在textview中顯示出來
1、沒加compose(this.<Long>bindToLifecycle())
當Activiry 結束掉以後,Observable還是會不斷的傳送數字,訂閱關係沒有解除
2、新增compose(this.<Long>bindToLifecycle())
當Activity結束掉以後,Observable停止傳送資料,訂閱關係解除。 -
從上面的例子可以看出
bindToLifecycle()
方法可以使Observable釋出的事件和當前的Activity繫結,實現生命週期同步。也就是Activity 的 onDestroy() 方法被呼叫後,Observable 的訂閱關係才解除。那能不能指定在Activity其他的生命狀態和訂閱關係保持同步,答案是有的。就是bindUntilEvent()
方法。這個逼裝的好累! -
bindUntilEvent( ActivityEvent event)
-
ActivityEvent.CREATE
: 在Activity的onCreate()方法執行後,解除繫結。 -
ActivityEvent.START
:在Activity的onStart()方法執行後,解除繫結。 -
ActivityEvent.RESUME
:在Activity的onResume()方法執行後,解除繫結。 -
ActivityEvent.PAUSE
: 在Activity的onPause()方法執行後,解除繫結。 -
ActivityEvent.STOP
:在Activity的onStop()方法執行後,解除繫結。 -
ActivityEvent.DESTROY
:在Activity的onDestroy()方法執行後,解除繫結。
//迴圈傳送數字 Observable.interval(0, 1, TimeUnit.SECONDS) .subscribeOn( Schedulers.io()) .compose(this.<Long>bindUntilEvent(ActivityEvent.STOP )) //當Activity執行Onstop()方法是解除訂閱關係 .observeOn( AndroidSchedulers.mainThread()) .subscribe(new Action1<Long>() { @Override public void call(Long aLong) { System.out.println("lifecycle-stop-" + aLong); textView.setText( "" + aLong ); } });
經過測試發現,當Activity執行了onStop()方法後,訂閱關係已經解除了。
上面說的都是訂閱事件與Activity的生命週期同步,那麼在Fragment裡面又該怎麼處理的? -
-
FragmentEvent
這個類是專門處理訂閱事件與Fragment生命週期同步的大殺器public enum FragmentEvent { ATTACH, CREATE, CREATE_VIEW, START, RESUME, PAUSE, STOP, DESTROY_VIEW, DESTROY, DETACH }
可以看出
FragmentEvent
和ActivityEvent
類似,都是列舉類,用法是一樣的。這裡就不舉例了!
總結
1、這三篇文章的相關程式碼示例都在 http://git.oschina.net/zyj1609/RxAndroid_RxJava
2、通過上面的三種方法,我相信你在專案中使用Rxjava的時候,已經能夠很好的控制了 Rxjava對記憶體的開銷。如果你有其他的方法或者問題,可以留言給我。