Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

RxJava RxLifecycle 生命周期 内存泄漏 MD

Demo地址

GitHub


目录

简介

另一个功能与此库类似、核心设计借鉴此库、此库作者也参与设计、此库作者认为比此库好、但是星星比较少、国内不流行、上手比较难的库:https://github.com/uber/AutoDispose

添加依赖

implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2'

完整依赖项:

implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.2' //基础库
implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.2' //Android中使用的库,内部引用了基础库,如果使用此库则无需再引用基础库
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2' //Android组件库,里面定义了例如RxActivity、RxFragment等Android组件,内部引用了基础库和Android库,如果使用此库则无需再重复引用
implementation 'com.trello.rxlifecycle2:rxlifecycle-components-preference:2.2.2' // Android使用的库,继承NaviActivity使用
implementation 'com.trello.rxlifecycle2:rxlifecycle-navi:2.2.2' //Android使用的库,继承LifecycleActivity使用,需要引入Google的仓库支持
implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.2.2' //使用AndroidLifecycle
implementation 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.2.2' // 支持Kotlin语法的RxLifecycle基础库
implementation 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle-kotlin:2.2.2' // 支持Kotlin语法的Android库

产生背景

随着 RxJava 及 RxAndroid 的逐渐推广,使用者越来越多,但是有一个问题,RxJava 的使用不当极有可能会导致内存泄漏,通常我们会有如下几种解决方案:

  • 解决方案1:手动为 RxJava 的每一次订阅进行控制,在指定的时机进行取消订阅。这种情况在订阅比较少的情况下没问题,但是如果非常多,没有意义的脏代码会让你写到吐。
  • 解决方案2:在 BaseActivity 中记录一个 List<Subscription> 或 List<Disposable>,每次使用后 add 进队列,在页面 onDestory 统一 unsubscribe() 或 dispose()。但是从一开始就发现这个方法实在是太搓了,脏代码并没有减少。
  • 解决方案3:后来发现很多人用一个类 CompositeSubscription,然而发现这个类仅仅是帮我们维护了一个 Set 而已,你妹,看起来高大上的样子,实际上屁都不是!

RxLifecycle 就是专门解决这一痛点的。一开始发现要让我们的 Activity 或 Fragment 继承自库中的类,就比较担心局限性,后来发现,这货这么做完全是为了帮我们省事呀,我们常用的一些比如 FragmentActivity、AppCompatActivity 等,基本都有相应的 Rx*** 类,实际使用时,我们只需将我们的 BaseActivity 改为实现它就行了。

该库允许基于另一个生命周期流[a second lifecycle stream]自动完成序列[automatically complete sequences]

此功能在Android中很有用,因为在Android中,不完整的订阅[incomplete subscriptions]可能导致内存泄漏。

注意

注意:【RxLifecycle 的原理是不是基于自动调用 unsubscribe 的】

RxLifecycle实际上并没有取消订阅[unsubscribe]序列。 相反,它终止[terminates]了序列。 它的表现方式因类型而异:

  • Observable、Flowable 和 Maybe:发出 onCompleted()
  • Single 和 Completable:发出onError(CancellationException)

如果序列需要 Subscription.unsubscribe() 行为,则建议您自己手动处理订阅并在适当时调用unsubscribe()。

使用方式 compose

您必须以表示生命周期流的 Observable <T> 开头。 然后使用 RxLifecycle 将序列绑定到该生命周期。

您可以在生命周期发出任何内容时进行绑定:

myObservable
.compose(RxLifecycle.bind(lifecycle))
.subscribe(...);
``` 或者您可以在特定生命周期事件发生时绑定:
```java
myObservable
.compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
.subscribe(...);
``` 或者,您可以让 RxLifecycle 确定结束序列的适当时间:
```java
myObservable
.compose(RxLifecycleAndroid.bindActivity(lifecycle))
.subscribe(...);
```
它假定您想要在相反的`[opposing]`生命周期事件中结束序列 - 例如,如果在 START 期间订阅,它将在 STOP 时终止。如果您在 PAUSE 之后订阅,它将在下一个销毁事件`[destruction event]`中终止,例如,PAUSE 将在 STOP 中终止。 # RxLifecycle
生命周期来自哪里? 通常,它们由适当的 `LifecycleProvider <T>` 提供。 但他们的实现`[implemented]`在哪里? 你有几个选择:
- 使用 rxlifecycle-components 中提供的 RxActivity,RxFragment 等类的子类
```java
public class MyActivity extends RxActivity {
@Override
public void onResume() {
super.onResume();
myObservable
.compose(bindToLifecycle()) //使用内置的 bindToLifecycle() 或 bindUntilEvent() 方法即可
.subscribe(...);
}
}
  • 使用 Navi + rxlifecycle-navi 生成:
public class MyActivity extends NaviActivity {
private final LifecycleProvider<ActivityEvent> provider = NaviLifecycle.createActivityLifecycleProvider(this);
@Override
public void onResume() {
super.onResume();
myObservable
.compose(provider.bindToLifecycle())
.subscribe();
}
}
  • 使用 Android 的 lifecycle + rxlifecycle-android-lifecycle 生成
public class MyActivity extends LifecycleActivity {
private final LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(this);
@Override
public void onResume() {
super.onResume();
myObservable
.compose(provider.bindToLifecycle())
.subscribe();
}
}
  • 自己编写实现

案例

public class RxBindingActivity extends RxFragmentActivity {
private Button btn;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rxbinding); btn = findViewById(R.id.btn);
RxView.clicks(btn) //点击获取验证码
.doOnNext(o -> btn.setEnabled(false))
.subscribe(o -> Observable.interval(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.take(10)
.compose(bindToLifecycle()) //绑定生命周期
.subscribe(aLong -> btn.setText(10 - aLong + " 秒"),
Throwable::printStackTrace,
() -> {
btn.setEnabled(true);
btn.setText("重新获取");
}));
} @Override
protected void onResume() {
super.onResume();
RxView.clicks(btn)
.buffer(1000, TimeUnit.MILLISECONDS, 5) //效果仅仅是,每隔1秒钟收集一下此1秒钟内的点击次数
.compose(bindUntilEvent(ActivityEvent.STOP))//在 onStop 时取消
.subscribe(list -> Log.i("【bqt】", "一秒钟内的点击次数:" + list.size()));
}
}

2018-9-15

RxJava RxLifecycle 生命周期 内存泄漏 MD的更多相关文章

  1. C语言基础 (10) 变量作用域,生命周期 内存结构

    01 课程回顾 1.指针数组 注意: 对于数组来说,在使用sizeof的时候a和&a[0]是不一样的, 虽然以%x打印出来他们都是地址 2.值传递 int a; fun(a); int *** ...

  2. LeakCanary检测内存泄漏.md

    一使用步骤 添加依赖 // 内存泄漏检测 debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4' releaseCompile ...

  3. Android性能优化之利用Rxlifecycle解决RxJava内存泄漏

    前言: 其实RxJava引起的内存泄漏是我无意中发现了,本来是想了解Retrofit与RxJava相结合中是如何通过适配器模式解决的,结果却发现了RxJava是会引起内存泄漏的,所有想着查找一下资料学 ...

  4. AutoDispose代替RxLifecycle优雅的解决RxJava内存泄漏问题

    使用过Rxjava的小伙伴都知道,在使用RxJava时如果处理不当,很可能会产生内存泄漏的问题. 我们使用rxjava最大的原因是响应式编程使我们的异步操作代码变得很优雅,在Android中,也使线程 ...

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

    rxjava rxandroid 赵彦军 前言:对Rxjava.Rxandroid不了解的同学可以先看看 RxJava 和 RxAndroid RxJava 和 RxAndroid 二(操作符的使用) ...

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

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

  7. autofac生命周期入门(如何避免内存泄漏)

    如果你是一个IOC新手,那么生命周期可能会比较难以理解.以至于谈到这个问题时,一些老手也时常表示疑虑和害怕.一个令人不安的问题就是-对象没有在合适的时机被销毁.这样一来内存的使用率就会一直攀升,直到程 ...

  8. JVM的内存管理、对象的生命周期、内存泄漏

    1 JVM内存 分为“堆”.“栈”和“方法区”三个区域,分别用于存储不同的数据 1.1 堆 JVM在其内存空间开辟一个称为”堆”的存储空间,这部分空间用于存储使用new关键字所创建的对象. 1.2 栈 ...

  9. LeakCanary 内存泄漏 监测 性能优化 简介 原理 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

随机推荐

  1. C语言结构体及typedef关键字定义结构体别名和函数指针的应用

    结构体(struct)的初始化 struct autonlist { char *symbol; struct nlist nl[2]; struct autonlist *left, *right; ...

  2. Linux——线程

    线程 我们都知道一个程序的执行是由进程来完成的,而进程里真正执行代码却是由线程来完成,它是真正的执行流.通常将一个程序⾥里一个执行路线就叫做线程(thread).对它更准确的定义是:线程是“一个进程内 ...

  3. 使用Docker中国官方镜像的加速地址

    vi /etc/docker/daemon.json # 添加如下内容 { "registry-mirrors": ["https://registry.docker-c ...

  4. x270

    https://thinkpad.lenovo.com.cn/product/93964.html

  5. Redis "MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk"问题的解决(转)

    今天第二次遇到Redis “MISCONF Redis is configured to save RDB snapshots, but is currently not able to persis ...

  6. oracle直接读写ms sqlserver数据库(二)配置透明网关

    环境说明: 数据库版本:11gR2 透明网关版本:11g 操作系统Windows Server2008_64位 ORACLE_HOME目录:D:\app\Administrator\product\1 ...

  7. TCP套接字端口复用SO_REUSEADDR

    下面建立的套接字都是tcp套接字 1.进程创建监听套接字socket1,邦定一个指定端口,并接受了若干连接.那么进程创建另外一个套接口socket2,并试图邦定同一个端口时候,bind错误返回“Add ...

  8. 在 DELPHI 中 procedure 型变量与 method 型变量的区别

    Procedure型变量: 在DELPHI中,函数.过程的地址可以赋给一个特殊类型的变量,变量可用如下方式声明: var p : procedure(num:integer); //过程 或: var ...

  9. Vue 插件写法

    都说Vue2简单,上手容易,但小马过河,自己试了才晓得,除了ES6语法和webpack的配置让你感到陌生,重要的是思路的变换,以前随便拿全局变量和修改dom的锤子不能用了,变换到关注数据本身.vue的 ...

  10. 一个完整的DLL远程注入函数

    函数名称: CreateRemoteDll() 返加类型:BOOL 接受参数: DLL路径,注入进程ID 其完整代码如下: BOOL CreateRemoteDll(const char *DllFu ...