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
    }

    可以看出FragmentEventActivityEvent 类似,都是枚举类,用法是一样的。这里就不举例了!

总结
1、这三篇文章的相关代码示例都在 http://git.oschina.net/zyj1609/RxAndroid_RxJava
2、通过上面的三种方法,我相信你在项目中使用Rxjava的时候,已经能够很好的控制了 Rxjava对内存的开销。如果你有其他的方法或者问题,可以留言给我。

RxJava 和 RxAndroid 四(RxBinding的使用)

RxJava 和 RxAndroid 三(生命周期控制和内存优化)的更多相关文章

  1. RxJava 和 RxAndroid (生命周期控制和内存优化)

    RxJava使我们很方便的使用链式编程,代码看起来既简洁又优雅.但是RxJava使用起来也是有副作用的,使用越来越多的订阅,内存开销也会变得很大,稍不留神就会出现内存溢出的情况,这篇文章就是介绍Rxj ...

  2. UIViewController生命周期控制

    UIViewController生命周期控制 UIViewController介绍 官方的介绍例如以下 The UIViewController class provides the fundamen ...

  3. Newbe.Claptrap 框架如何实现多级生命周期控制?

    Newbe.Claptrap 框架如何实现多级生命周期控制?最近整理了一下项目的术语表.今天就谈谈什么是 Claptrap Lifetime Scope. 特别感谢 kotone 为本文提供的校对建议 ...

  4. Vue.js 子组件的异步加载及其生命周期控制

    前端开发社区的繁荣,造就了很多优秀的基于 MVVM 设计模式的框架,而组件化开发思想也越来越深入人心.这其中不得不提到 Vue.js 这个专注于 VM 层的框架. 本文主要对 Vue.js 组件化开发 ...

  5. vue学习三:生命周期钩子

    生命周期钩子介绍: 每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听.编译模板.将实例挂载到 DOM 并在数据变化时更新 DOM 等.同时在这个过程中也会运行一些叫做生 ...

  6. 管中窥豹——从对象的生命周期梳理JVM内存结构、GC调优、类加载、AOP编程及性能监控

    如题,本文的宗旨既是透过对象的生命周期,来梳理JVM内存结构及GC相关知识,并辅以AOP及双亲委派机制原理,学习不仅仅是海绵式的吸收学习,还需要自己去分析why,加深对技术的理解和认知,祝大家早日走上 ...

  7. Docker 基本概念(三)-生命周期详解(镜像、容器、仓库)

    Docker三大组件:镜像.容器.仓库.  一.镜像 1 从仓库获取镜像 #一.从仓库获取镜像,帮助命令:docker pull -help 命令:docker pull [选项] [docker R ...

  8. UIViewController生命周期控制-开发规范

    从网上各位iOS们收集并总结: 各方法使用: init 中初始化一些UI组件,比如UIButton,UILabel等 loadView 中 createFields 接受参数,初始化变量 create ...

  9. iOS UIViewController生命周期控制

    具体流程,看下图: init方法在init方法中实例化必要的对象(遵从LazyLoad思想)init方法中初始化ViewController本身 loadView方法当view需要被展示而它却是nil ...

随机推荐

  1. SURF算子(1)

    SURF算子,参考这篇文章的解释http://www.ipol.im/pub/art/2015/69/ SURF 是   Speeded Up Robust Features 加速鲁棒特征的含义. T ...

  2. postgres中几个复杂的sql语句

    postgres中几个复杂的sql语句 需求一 需要获取一个问题列表,这个问题列表的排序方式是分为两个部分,第一部分是一个已有的数组[0,579489,579482,579453,561983,561 ...

  3. 通过自定义相册来介绍photo library的使用

    因为我在模仿美图秀秀的功能,在使用相册时候,UIImagePickerController本来就是一个UINavigationController的子类,所以没有办法使用push,所以做了一个自定义的 ...

  4. SQL Server获取下一个编码字符实现继续重构与增强

        我在SQL Server获取下一个编码字符实现的博文中,虽然实现了这个问题,但是感觉维护起来比较麻烦,例如如果调整编码字符串的固定长度,就需要变更三个函数,这样的为何成本确实比较大.面向对象编 ...

  5. EDNS

    随着业务的复杂化和多样化,RFC1035中定义的DNS消息格式和它支持的消息内容已经不足以满足一些DNS服务器的需求,于是,RFC2671中提出了一种扩展DNS机制EDNS(Extension Mec ...

  6. ASP.NET MVC 请求流程:Controller

    1.请求进入时,.NET Framework就找出所有的HttpModule,以此调用它们的Init方法,如下图所示,我们重点关注"UrlRoutingModule-4.0"的Ht ...

  7. CSRF 防御策略

    在业界目前防御 CSRF 攻击主要有三种策略:验证 HTTP Referer 字段:在请求地址中添加 token 并验证:在 HTTP 头中自定义属性并验证.下面就分别对这三种策略进行详细介绍. 验证 ...

  8. 【Java每日一题】20161103

    package Nov2016; import java.util.List; public class Ques1103 { public void method01(String[] array) ...

  9. ListView 使用 LiveBindings 显示超过 200 条记录

    ListView 使用 LiveBindings 预设加载 200 条记录,这也许是速度的考量,但当需要全部加载的的情况时,该如何做呢?只需加入下面二行代码即可: FDQuery1.OptionsIn ...

  10. FreeBSD应该装gnome3做桌面

    目前freebsd pkg包管理体系的repo源多了一些,速度快了很多. 仓库中目前的版本为3.14,安装gnome3很简单. pkg install xorg gnome3 echo "e ...