Android干货

Rxjava常规使用及内存泄漏问题

2021-03-11  本文已影响0人  gogoingmonkey

前言

目前很多项目使用retrofit+Rxjava+mvp的架构开发项目还是比较多的。最近在改一处内存泄漏时候问题时,遇到一个Rxjava相关的泄漏问题。项目中虽然用Rxjava的地方不多,但是项目中用到的东西,还是尽可能搞懂用法、原理。让心里踏实点。

目录

1.本篇主要说下 retrofit+Rxjava的基本用法,及Rxjava内存泄漏相关;
2.主要说下Rxjava实现原理(源码分析);https://www.jianshu.com/p/5d96318b0c03

常规使用

1.添加依赖文件,主要说一点,不要添加那些不必要的依赖;

    // 依赖RxAndroid 2X 的依赖库
    // 增加RxJava 2X 的依赖库
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
    implementation 'io.reactivex.rxjava2:rxjava:2.0.7'

    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
    implementation "com.squareup.retrofit2:converter-gson:2.4.0"

2.定义retrofit接口

public interface WanAndroidApi {

     // 总数据
    @GET("project/tree/json")
    Observable<ProjectBean> getProject();  // 异步线程 耗时操作

    // ITem数据
    @GET("project/list/{pageIndex}/json") // ?cid=294
    Observable<ProjectItem> getProjectItem(@Path("pageIndex") int pageIndex, @Query("cid") int cid);  // 异步线程 耗时操作
}public interface MockApi {

     // 总数据
    @GET("project/tree/json")
    Observable<AllBean> getProject();  // 异步线程 耗时操作

    // ITem数据
    @GET("project/list/{pageIndex}/json") // ?cid=294
    Observable<ItemBean> getProjectItem(@Path("pageIndex") int pageIndex, @Query("cid") int cid);  // 异步线程 耗时操作
}

解释下上面代码
定义了两个接口,一个是获取所有数据的,一个是通过页数和cid,获取每条数据,数据是真实数据,WanAndroid 提供的。

3.定义下载工具类

public class HttpUtils {

    /**
     * 默认 test-a环境
     */
    public static String BASE_URL = "https://www.wanandroid.com/";

    public static void setBaseUrl(String baseUrl) {
        BASE_URL = baseUrl;
    }

    public  static  Retrofit  getRetrofitInstance(){

                 // OKHttp客户端
        OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
        // 各种参数配置
        OkHttpClient okHttpClient = httpBuilder
//                .addNetworkInterceptor(new StethoInterceptor())
                .readTimeout(10000, TimeUnit.SECONDS)
                .connectTimeout(10000, TimeUnit.SECONDS)
                .writeTimeout(10000, TimeUnit.SECONDS)
                .build();

        return  new Retrofit.Builder().baseUrl(BASE_URL)
                  // TODO 请求用 OKhttp
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();

    }
}

里面代码也比较简单。

4.调用


 private MockApi api;

 api = HttpUtils.getRetrofitInstance().create(MockApi.class);  //拿到接口对象
// 获取网络API
        subscribe = api.getProject() //  Observable<ProjectBean>
                .subscribeOn(Schedulers.io()) // 上面 异步
                .observeOn(AndroidSchedulers.mainThread()) // 下面 主线程
                .subscribe(new Consumer<ProjectBean>() {
                    @Override
                    public void accept(@NonNull ProjectBean projectBean) throws Exception {
                        Log.d(TAG, "accept: " + projectBean); // UI 可以做事情
                    }
                });

这样就实现了简单的网络请求,并打印数据

注意点

1.retrofit并不支持网络请求,是对OKhttp的封装;
2.请求到的数据交给Rxjava 处理而已,你如果不用也是没问题的;

Rxjava内存泄漏

1.哪些场景会出现

使用RxJava发布一个订阅后,当页面被finish,此时订阅逻辑还未完成,如果没有及时取消订阅,就会导致Activity/Fragment无法被回收,从而引发内存泄漏.场景还比较多:Activity中执行异步任务、Presenter或ViewModel中执行异步任务、Manager、Adapter相关类中执行异步任务。
如果代码如下:

Observable.create(new ObservableOnSubscribe<XXX>() {
            @Override
            public void subscribe(final ObservableEmitter<XXX> emitter) throws Exception {
                Observable.zip(.....)
                      .subscribeOn(Schedulers.io())
                      .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Consumer<ImpressionBean>() {
                            @Override
                            public void accept(XXX impressionBean) throws Exception {
                                emitter.onNext(impressionBean);
                            }
                        }, new Consumer<Throwable>() {
                            @Override
                            public void accept(Throwable throwable) throws Exception {
                                emitter.onNext(new XXX());
                            }
                        });
            }
        });
2.如何避免

把整个Observable.create() ...执行subscribe()方法后赋值为Disposable,然后再销毁页面调用下面方法

 if (disposable != null && !disposable.isDisposed()) {

        disposable.dispose();

        }

Presenter或ViewModel中执行异步任务,自定义控件,Manager相关类,自定义Adapter中执行异步任务应该如何防止内存泄露?

在BaseActivity中实现代码:

private CompositeDisposable mCompositeDisposable = new CompositeDisposable();

public void addDisposable(Disposable disposable) {

        mCompositeDisposable.add(disposable);

        }

@Override

protected void onDestroy() {

        super.onDestroy();

        mCompositeDisposable.dispose();

        }

每次Rxjava异步任务时,把相关的disposable对象传入,onDestroy中统一解绑

在Activity的onDestory()生命周期时,自动解除订阅,以防止因生命周期组件的生命周期而导致的RxJava内存泄漏事件。

其他的解决方式

Rxlife解决内存泄露
autoDisposable解决内存泄露
RxLifecycle解决内存泄露

上一篇下一篇

猜你喜欢

热点阅读