这样,你才能算会 RxJava、RxAndroid 之取消订阅
一:概述
前几天app
总是空指针奔溃,发现为某个 Fragment
中的控件为null
导致的。而且这个Fragment
是能够正常显示的。那么为什么还会空指针呢?
二:问题排查
- 这个
app
使用了AndroidAnnotations
注解。要了解为什么Fragment
中控件为null
的原因,就需要找到框架AndroidAnnotations
在Fragment
新建时初始化控件方式,以及在Fragment
销毁时对控件的处理方法。 - 经排查,发现
Fragment
销毁时AndroidAnnotations
会把所有的控件置为null
。 - 再次进入
Fragment
时 ,Fragment
为新建的Fragment
实例,并没有复用原来的Fragment
,里面的控件也正确初始化了。 - 那么,显然问题不在这里。
app
还采用了RxJava、RxAndroid
,并且Rx
观察者的call
方法里有对Fragment
的控件调用,那么很可能内存泄漏了,Fragment 并没有正确的销毁。Fragment
中的Rx
观察者能正常接收到订阅信息,然后去执行对控件的操作,此时控件已经为null
,那么空指针已经不可避免。
三: 取消 Rxjava、RxAndroid 订阅的方法
一般用过 Rxjava
的人都知道,在Activity
、Fragment
销毁时,需要取消订阅。取消订阅的方式有多种,如下
用框架管理 RxJava ,如 使用
trello/RxLifecycle
开源库或知乎同名开源库zhihu/RxLifecycle
,可参考这篇文章,这里不多赘述,网上的文章也挺多的。不使用开源库,使用类
CompositeSubscription
的add 、unsubscribe
等方法管理取消订阅
四: 使用类 unsubscribe 取消订阅
由于引入框架还需要添加依赖,无疑会增加安装包的大小,所以我这里选择使用封装 RxJava
本身自带的API
去管理取消订阅。
1. 了解 CompositeSubscription
CompositeSubscription
用来表示一起取消订阅的一组订阅的订阅。从构造方法可以知道CompositeSubscription
内部存在一个HashSet
用来存储需要一起取消订阅的Subscriptions
- 调用
add
方法将Subscription
加入到Hashset
中。若Hashset
中的Subscriptions
还没有取消订阅,则把新的Subscription
加入到Hashset
中。如果已经取消订阅,则也取消该Subscription
的订阅
public void add(final Subscription s) {if (s.isUnsubscribed()) {return;}if (!unsubscribed) {synchronized (this) {if (!unsubscribed) {if (subscriptions == null) {subscriptions = new HashSet<Subscription>(4);}subscriptions.add(s);return;}}}// call after leaving the synchronized block so we're not holding a lock while executing thiss.unsubscribe();}
- 调用
unsubscribe
方法遍历取消Haset
中的所有订阅,包括它自己。如果此时还有新的Subscription
加入进来,则也取消该Subscription
的订阅。
@Overridepublic void unsubscribe() {if (!unsubscribed) {Collection<Subscription> unsubscribe = null;synchronized (this) {if (unsubscribed) {return;}unsubscribed = true;unsubscribe = subscriptions;subscriptions = null;}// we will only get here onceunsubscribeFromAll(unsubscribe);}}private static void unsubscribeFromAll(Collection<Subscription> subscriptions) {if (subscriptions == null) {return;}List<Throwable> es = null;for (Subscription s : subscriptions) {try {s.unsubscribe();} catch (Throwable e) {if (es == null) {es = new ArrayList<Throwable>();}es.add(e);}}Exceptions.throwIfAny(es);}
2. 最佳实践
- 定义
BaseActivity
或BaseFragment
.具体看代码吧!
BaseActivity
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;import rx.subscriptions.CompositeSubscription;public class BaseActivity extends AppCompatActivity {public CompositeSubscription compositeSubscription;@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);compositeSubscription = new CompositeSubscription();}@Overrideprotected void onDestroy() {super.onDestroy();//RX生命周期管理if (compositeSubscription != null && !compositeSubscription.isUnsubscribed())compositeSubscription.unsubscribe();}
}
BaseFragment
public class BaseFragment extends Fragment {public CompositeSubscription compositeSubscription;@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);compositeSubscription = new CompositeSubscription();}@Overridepublic void onDestroyView() {super.onDestroyView();//RX生命周期管理if (compositeSubscription != null && !compositeSubscription.isUnsubscribed())compositeSubscription.unsubscribe();}
}
- 让需要使用
RxJava
的Activity
继承BaseActivity
,让需要使用RxJava
的Fragment
继承BaseFragment
. - 调用
CompositeSubscription
的add
方法把订阅产生的Subscription
加入到compositeSubscription
中去。
3. 分析:
- 在订阅产生时,将订阅加入到
CompositeSubscription
中。 - 在
Activity
、Fragment
销毁时,统一取消所有订阅。
五:总结:
注意:不管是使用框架还是RxJava
自带方法,都要在Activity
、Fragment
销毁时,取消订阅,防止内存泄漏、奔溃等问题。
这样,你才能算会 RxJava、RxAndroid 之取消订阅相关推荐
- Android 基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器aaa
MDPlayer万能播放器 MDPlayer,基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器,可以播 ...
- 基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器
MDPlayer万能播放器 MDPlayer,基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器,可以播 ...
- RxJava/RxAndroid:timer(long delay, TimeUnit unit)
RxJava/RxAndroid:timer(long delay, TimeUnit unit) timer起到定时器的作用,本例使用timer延迟3秒执行一个输出任务: package com.e ...
- RxJava Rxandroid 结合 Retrofit 使用
其实Retrofit会了.集合RxJava,RxAndroid 就很简单了. 只需要改几个地方. 1.接口里面返回的对象不再是 call,而是Observable public interface A ...
- java 安卓下载文件_GitHub - Charay/downloadfile: 使用Retrofit2+Rxjava+Rxandroid+okhttp的方式下载文件并存储到sd卡指定目录...
downloadfile 使用Retrofit2+Rxjava+Rxandroid+okhttp的方式下载文件并存储到sd卡指定目录 使用: gradle Step 1.在工程build.gradle ...
- 3. fooView rxjava + rxandroid + retrofit 安卓开发框架搭配 az kj
3. fooView rxjava + rxandroid + retrofit 转载于:https://www.cnblogs.com/cczh/p/9724382.html
- 什么样的域名才能算短域名?短域名还能有吗?
众所周知,域名越短越好,短域名便于用户记忆,同时也更有价值.这里有人要问了,什么样的域名才能算短域名吗?现如今短域名还能有吗?以下是小聚给大家的介绍. 1.什么样的域名才能算短域名? 短域名就是字符短 ...
- 姓名学三才数理怎么算?怎样才能算吉凶?姓名打分PHP源码
一.姓名三才数理的计算原理 三才配置中,三才数理怎么算?怎么样才能算出三才吉凶?三才配置是利用五行生克之理来推断人的吉凶的.因为五行则是对世界万物更为细致的分析,古人认为,世界万物是由木.火.土.金. ...
- 【机器学习】用特征量重要度(feature importance)解释模型靠谱么?怎么才能算出更靠谱的重要度?
[机器学习]用特征量重要度(feature importance)解释模型靠谱么?怎么才能算出更靠谱的重要度? 我们用机器学习解决商业问题的时候,不仅需要训练一个高精度高泛化性的模型,往往还需要解释哪 ...
最新文章
- Shiro快速入门 —— 9.freemaker使用shiro标签
- js createElement appendChild createTextNode用法
- dede服务器建站_建站就是这么简单(内容系统管理CMS篇)
- Android中Context简介
- 想要导航提示页最新安卓区_最新微信小程序授权的详细处理思路(一)
- matlab swt函数,matlab swt 函数出错
- python 字节码操作_从操作码和参数列表创建Python字节码?
- linux shell 脚本中 字符串截取并赋值引用
- 基于matlab的信号频谱分析 开题报告,基于MATLAB的数字信号处理开题报告
- 安装Android SDK时无法识别JDK 10
- PHP中单引号与双引号用法
- 听小S教你如何瘦小腿
- LSM6DS3(六轴传感器)STM32驱动及6D功能实现
- S32K144(2)时钟配置
- 刘慈欣回应《流浪地球》热点问题:承认有些设定有bug...
- Inksape 设置画布像素尺寸及透明背景
- [免费视频教程]UI自动化测试之Jenkins配置教程
- STK与VC++联合编程实战(第三回:加入卫星对象)
- 英文学习20180201
- 【二十四】Python全栈之路--装饰器