一.背景
在项目中使用Retrofit+Rxjava的过程中,如果代码编写思量不够就会引入内存泄漏。对内存的解决方案目前存在三种,第一种是在适当的时候解除对网络请求的订阅;第二种是采用RxlifeCycle;第三种是采用AutoDisPose。
二.Retrofit和Rxjava使用中的内存泄漏
在说明Retrofit和Rxjava的内存泄漏前,先查看一下它们结合使用的常用代码如下:
//Service
接口的代码
public
interface
ServiceApi
{
@GET
(
"/user/info"
)
Observable<Response>
getUserInfo
(@Query(
"userId"
) String userId);
}
//
在
Activity
通过
Retrofit
获取用户信息,
Retrofit
的构造信息在此略过
private
void
getUserInfo
(){
subscription = serviceApi.getUserInfo(
"001"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new
Action1<Response>() {
@Override
public
void
call
(Response response) {
String content =
new
String(((TypedByteArray) response.getBody()).getBytes());
userInfo.setText(content);
}
},
new
Action1<Throwable>() {
@Override
public
void
call
(Throwable throwable) {
throwable.printStackTrace();
}
});
}
|
上面是很常见的Retrofit和Rxjava结合使用的代码,上面使用的代码中有一个问题就是subscribe函数中的内部对象"new Action"会持有了Activity的引用,如果在关闭Activity过程中,retrofit的网络请求仍在继续,内部对象Activity1对Activity仍然持有引用,就会导致Activity对象不会被销毁造成内存泄漏。
三.内存泄漏的解决方案
第一种方案:解除对网络请求的订阅
//在Activity通过Retrofit获取用户信息,Retrofit的构造信息在此略过
private
void
getUserInfo
(){
subscription = serviceApi.getUserInfo(
"001"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.onTerminateDetach()
//在取消订阅时解除上游生成者和下游订阅者间的引用
.subscribe(
new
Action1<Response>() {
@Override
public
void
call
(Response response) {
String content =
new
String(((TypedByteArray) response.getBody()).getBytes());
userInfo.setText(content);
}
},
new
Action1<Throwable>() {
@Override
public
void
call
(Throwable throwable) {
throwable.printStackTrace();
}
});
}
@Override
public
void
onDestroy
() {
super
.onDestroy();
if
(subscription !=
null
&& !subscription.isUnsubscribed()) {
subscription.unsubscribe();
//在Activity结束时解除订阅关系
}
}
|
第一种方案实施起来,要么在每个使用Retrofit的Activity页面中都进行一次解除订阅,要么自己完成一个代码的封装。如果采用Rxlifecycle或AutoDispose代码就会简洁和可靠很多。
第二种方案:采用Rxlifecycle框架
关于Rxlifecycle的使用介绍博客很多,比如可以参考如下博客文档:
https://blog.csdn.net/mq2553299/article/details/78927617
第三种方案:采用AutoDispose框架
四.Rxlifecycle的原理说明
1.Activity中调用Rxlifecycle的代码如下:
// Specifically bind this until onPause()
Observable.
interval
(
1
, TimeUnit.
SECONDS
)
.doOnDispose(
new
Action() {
@Override
public void
run()
throws
Exception {
Log.
i
(
TAG
,
"Unsubscribing subscription from onCreate()"
);
}
})
.compose(
this
.<Long>bindUntilEvent(ActivityEvent.
PAUSE
))
//指定在Activity调用onPause时解除对事件的绑定
.subscribe(
new
Consumer<Long>() {
@Override
public void
accept(Long num)
throws
Exception {
Log.
i
(
TAG
,
"Started in onCreate(), running until onPause(): "
+ num);
}
});
|
2.compose是对Observable观察流进行转换,将一类Observable转换成另一类Observable,查看bindUntilEvent代码如下:
@Override
@NonNull
@CheckResult
public final
<
T
> LifecycleTransformer<
T
> bindUntilEvent(
@NonNull
ActivityEvent event) {
return
RxLifecycle.
bindUntilEvent
(
lifecycleSubject
, event);
}
|
其中lifecycleSubject属于另一个Observable,会在Activity生命周期的每一个阶段发出事件来。
3.继续跟踪源码bindUntileEvent,如下,可以看到在lifecycle返回和event相同的事件时,才会返回一个Observable。
*/
@Nonnull
@CheckReturnValue
public static
<
T
,
R
> LifecycleTransformer<
T
> bindUntilEvent(
@Nonnull
final
Observable<
R
> lifecycle,
@Nonnull
final
R
event) {
checkNotNull
(lifecycle,
"lifecycle == null"
);
checkNotNull
(event,
"event == null"
);
return
bind
(
takeUntilEvent
(lifecycle, event));
}
private static
<
R
> Observable<
R
> takeUntilEvent(
final
Observable<
R
> lifecycle,
final
R
event) {
return
lifecycle.filter(
new
Predicate<
R
>() {
@Override
public boolean
test(
R
lifecycleEvent)
throws
Exception {
return
lifecycleEvent.equals(
event
);
}
});
}
|
4.上面的bindUntilEvent会返回一个LifecycleTransformer对象,该对象在bind函数中生成,在LifecycleTransform类中实现了接口函数apply
@Nonnull //
bind函数
@CheckReturnValue
public static
<
T
,
R
>
LifecycleTransformer
<
T
> bind(
@Nonnull
final
Observable<
R
> lifecycle) {
return new
LifecycleTransformer
<>(lifecycle);
}
|
@ParametersAreNonnullByDefault
public final class
LifecycleTransformer<
T
>
implements
ObservableTransformer<
T
,
T
>,
FlowableTransformer<
T
,
T
>,
SingleTransformer<
T
,
T
>,
MaybeTransformer<
T
,
T
>,
CompletableTransformer
{
final
Observable<?>
observable
;
LifecycleTransformer(Observable<?> observable) {
checkNotNull
(observable,
"observable == null"
);
this
.
observable
= observable;
}
@Override
public
ObservableSource<
T
> apply(Observable<
T
> upstream) {
//apply接口函数的实现
return
upstream.takeUntil(
observable
);
}
|
apply函数会在compose调用的时候去执行。takeUntil表示当observable发送事件流的时候,upstream就会停止发送事件流,并解除上下流之间的引用关系。
五.总结
方案二的实现过程就是,在调用时指定一个Activity的截止事件;在基类中构造一个产生事件的Observable,该Observable发送流的时机在选择在所产生的事件等于截止事件时;然后在调用的实现方法中判断当有流产生时,就截止原本的流。有点绕,但是大致是这么个意思。方案三和方案二的实现原理类似,区别在于方案二需要通过继承
RxAppCompatActivity或RxFragment来实现,而方案三则只需以组合的方式就可以完成,灵活性要高于方案二。
参考链接