RxJava 1中调用unsubscribe()无法取消Observable执行的问题求助
为什么RxJava的unsubscribe没终止你的网络请求?
这问题我之前也踩过坑!其实核心原因是:RxJava的unsubscribe()并不会直接终止正在执行的fromCallable代码块——它只是切断了观察者和被观察者的联系,不会主动中断线程或者强制停止你的网络请求。
问题根源
Observable.fromCallable()里的代码是在独立线程中执行的(如果你配置了subscribeOn(Schedulers.io())的话),Java本身没有安全的强制终止线程的机制,RxJava也不会帮你做这件事。所以即使你调用了unsubscribe(),只要你的网络请求代码没处理取消逻辑,它就会一直跑完。
解决办法,分三种场景给你方案:
1. 如果你用的是支持取消的网络库(比如OkHttp/Retrofit)
直接在代码中持有请求的引用,取消订阅时主动终止请求:
// 先定义一个集合存pending的请求 private List<Call> mPendingNetworkCalls = new ArrayList<>(); private Subscription mSearchSubscription = null; // 创建Observable的时候 mSearchSubscription = Observable.fromCallable(() -> { for (/* 你的大量网络请求循环 */) { // 创建OkHttp请求 Request request = new Request.Builder().url("你的接口").build(); Call call = okHttpClient.newCall(request); mPendingNetworkCalls.add(call); try { Response response = call.execute(); // 处理响应... return response.body().string(); } catch (IOException e) { throw e; } finally { mPendingNetworkCalls.remove(call); } } }) .subscribeOn(Schedulers.io()) .subscribe(/* 执行相关操作 */); // Activity销毁时 if (mSearchSubscription != null){ mSearchSubscription.unsubscribe(); } // 主动取消所有未完成的请求 for (Call call : mPendingNetworkCalls) { call.cancel(); } mPendingNetworkCalls.clear();
2. 手动检查线程中断状态
如果你的网络请求是循环执行的,可以在每次循环前检查当前线程是否被中断(RxJava调用unsubscribe()时会给线程发中断信号):
mSearchSubscription = Observable.fromCallable(() -> { for (/* 大量网络请求的循环 */) { // 检查线程是否被中断,是的话抛出异常终止执行 if (Thread.currentThread().isInterrupted()) { throw new InterruptedException("订阅已取消,终止任务"); } // 执行单个网络请求... } return 最终结果; }) .subscribeOn(Schedulers.io()) .subscribe( /* 成功回调 */, throwable -> { // 捕获中断异常,做清理工作 if (throwable instanceof InterruptedException) { Log.d("TAG", "任务已被取消"); } } );
3. 改用Observable.create()手动控制订阅状态
如果不想依赖线程中断,可以用create()创建Observable,每次执行前检查订阅状态:
mSearchSubscription = Observable.create(subscriber -> { try { for (/* 大量网络请求循环 */) { // 先检查是否已经取消订阅,是的话直接退出 if (subscriber.isUnsubscribed()) { break; } // 执行网络请求... // 发送结果给观察者 subscriber.onNext(单次请求结果); } subscriber.onCompleted(); } catch (Exception e) { subscriber.onError(e); } }) .subscribeOn(Schedulers.io()) .subscribe(/* 处理结果 */);
关键提醒
不管用哪种方法,核心都是你要自己在业务代码中处理取消逻辑——RxJava只负责通知你订阅已取消,不会替你终止正在跑的任务。
内容的提问来源于stack exchange,提问作者masztalski
相关产品推荐
相关产品推荐

