天天看點

RxJava 和 RxAndroid 三(生命周期控制和記憶體優化) RxJava 和 RxAndroid 四(RxBinding的使用)

rxjava

rxandroid

趙彥軍

前言:對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對記憶體的開銷。如果你有其他的方法或者問題,可以留言給我。

RxJava 和 RxAndroid 四(RxBinding的使用)