1. 程式人生 > >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 框架的使用

  • 在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
    }
    

    可以看出FragmentEventActivityEvent 類似,都是列舉類,用法是一樣的。這裡就不舉例了!

總結
1、這三篇文章的相關程式碼示例都在 http://git.oschina.net/zyj1609/RxAndroid_RxJava
2、通過上面的三種方法,我相信你在專案中使用Rxjava的時候,已經能夠很好的控制了 Rxjava對記憶體的開銷。如果你有其他的方法或者問題,可以留言給我。

相關推薦

RxJava RxAndroid 生命週期控制記憶體優化

rxjava rxandroid 趙彥軍 RxJava使我們很方便的使用鏈式程式設計,程式碼看起來既簡潔又優雅。但是RxJava使用起來也是有副作用的,使用越來越多的訂閱,記憶體開銷也會變得很大

表單資料的蒐集react元件的生命週期

四:表單資料的蒐集 (1)         問題: 在react應用中, 如何收集表單輸入資料 (2)         包含表單的元件分類

RxJava RxAndroidRxBinding的使用

對Rxjava不熟悉的同學可以先看我之前寫的幾篇文章 前言:RxBinding 是 Jake Wharton 的一個開源庫,它提供了一套在 Android 平臺上的基於 RxJava的 Binding API。所謂 Binding,就是類似設定 OnClickListener 、設定

RxJava RxAndroid操作符的使用

前言:對Rx不瞭解的朋友可以先看我的第一篇博文 ,是對Rxjava的基本介紹 1、merge操作符,合併觀察物件 19 List<String> list1 = new ArrayList<>() ; 20 List<String&g

RxJava RxAndroid執行緒排程

對rxJava不瞭解的同學可以先看 本文將有幾個例子說明,rxjava執行緒排程的正確使用姿勢。 例1 Observable .create(new Observable.OnSubscribe<String>() {

多線程線程組線程池

@override executors cpu eight death java 7 中斷 屬於 空閑 線程組和線程池 一. 線程組 1. 線程組介紹及使用 Java使用ThreadGroup來表示線程組,它可以對一批線程進行分類管理,Java允許直接對線程組進行控制。對線

跨域講解學習服務器NginxApache配置

ati 服務器 json servle imp return 進行 xtra alt 問題一、什麽是虛擬主機?   多個域名指向同一個服務器,服務器根據不同的域名把請求轉到不同的應用服務器。 問題二、什麽是反向代理?   反向代理方式是指以代理服務器來接受internet上

Libgdx Developer's Guide(Libgdx開發者手冊)-5生命週期

Libgdx擁有一個設計非常好的生命週期以管理應用程式狀態,比如建立,暫停和恢復,渲染和銷燬應用程式。 ApplicationListener 應用開發者通過實現 ApplicationListener 介面並傳入一個實現了應用的例項來掛接到生命週期事件,該應用實現了一個指定的後臺 (see

React 學習筆記 生命週期

<Lifecycle></Lifecycle> 元件載入時觸發的函式 constructor —> componentWillMount —> render —> componentDidMount import React, {

JPA 實體生命週期理解總結(轉)

(1)前言: 最近在使用Spring Data Jpa開發的時候,發現更新單個物件的時候,可以這麼寫:  @Transactional(value = "oracleTM")  public E update(Serializable id, E newEntity)

Android--四大元件之BroadCastReceiver生命週期、實現原理及使用等

####1. BroadCastReceiver是什麼? ####2. 廣播型別 ######1). 有序廣播 ######2). 無序廣播 ####3. 生命週期 ####4. 實現原理 ####5. 使用方法 ####6. 許可權問題(安全性) ####7. LocalBroad

Cocos Creator學習生命週期回撥函式

1.目的:學習生命週期回撥函式以及回撥順序,更有利於我們邏輯的處理把控。   2.生命週期回撥函式: 節點:指cc.Node;元件:指cc.Component。 ①onLoad:指令碼元件繫結的節點所在場景載入時系統回撥一次(或者節點active從false變為true時系統回撥一次)。可在

手遊LTV生命週期價值計算公式

在承接APP推廣專案中,手遊價值變現最直接,核心是獲取更多的充值,其中LTV(Lifetime-Value生命週期價值)是一個重要參考指標,可以理解為玩家在其生命週期內對遊戲的平均貢獻值,為什麼要計算LTV呢? 一、LTV 的用途 在遊戲進入市場推廣階段後,手遊LTV可以有以下兩點用途:

ViewController的生命週期分析使用

iOS的SDK中提供很多原生ViewController,大大提高了我們的開發效率,下面是我的一些經驗。 一、結構 按結構可以對iOS的所有ViewController分成兩類: 1、主要用於展示內容的ViewController,這種ViewController主要用於

Autofac學習之生命週期:InstancePerLifetimeScope、SingleInstance、InstancePerDependency

InstancePerLifetimeScope:同一個Lifetime生成的物件是同一個例項 SingleInstance:單例模式,每次呼叫,都會使用同一個例項化的物件;每次都用同一個物件; InstancePerDependency:預設模式,每次呼叫,都會重新

第五章 運輸層UDPTCP次握手,四次揮手分析

    序言         通過這章,可以知道其實三次握手和四次揮手其實真的好簡單,通過這章的學習,我相信你也會同樣的認為,以後在也不需要聽到別人問三次握手的過程而自己一臉懵逼了,覺得人家好屌,其實也就是他懂你不懂,僅此而已,不懂就去學。學了你就會覺得其實也就那樣,沒有什麼厲害的,這讓我回想以前剛學習程式設

python 全棧開發,Day84(django請求生命週期,FBVCBV,ORM拾遺,Git)

一、django 請求生命週期 流程圖: 1. 當用戶在瀏覽器中輸入url時,瀏覽器會生成請求頭和請求體發給服務端請求頭和請求體中會包含瀏覽器的動作(action),這個動作通常為get或者post,體現在url之中. 2. url經過Django中的wsgi,再經過Django的中介軟

Vue的生命週期函式beforeRouteEnter()/beforeRouteLeave()的函式

用Vue開發了一個專案,雖然專案做完了,但心中卻沒有一個完整的知識體系,不能稱之為會Vue,也許只能稱之為了解,這段時間閒剩下來,找到Vue.js 的官網,簡直了。。。簡直都是自己陌生的各種語法函式,都懷疑自己是怎麼做的專案啦! 先參考vue官網從簡單的看起!先了解下vue的生命週期。 &n

Java執行緒的6種狀態及切換生命週期

轉自:https://blog.csdn.net/pange1991/article/details/53860651/ Java中執行緒的狀態分為6種。 1. 初始(NEW):新建立了一個執行緒物件,但還沒有呼叫start()方法。2. 執行(RUNNABLE):Java執行緒中將就緒(r

maven的常用命令maven專案的生命週期

一.maven的常用命令 1.clean:清理 A.java中的clean命令 選中一個專案clean會把你生成的.class檔案清理掉 B.Tomcat中的clean命令 To