android 多线程下载retrofit,android – 在我更新到Retrofit 2.0之后,在不同的线程中发布了对onNext的onNext调用...

在我们使用Retrofit 1.9时,我的同事创建了以下课程

public class SomeApiCallAction {

private Subscription subscription;

private NoInternetConnectionInterface noInternetConnectionInterface;

public interface NoInternetConnectionInterface {

PublishSubject noInternetConnection(Throwable throwable);

}

public void execute(Subscriber subscriber, NoInternetConnectionInterface noInternetConnectionInterface) {

this.noInternetConnectionInterface = noInternetConnectionInterface;

this.subscription = retrofit.someService().someApiCall()

.subscribeOn(Schedulers.newThread())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(subscriber)

.retryWhen(retryFunction);

}

public void cancel() {

if (this.subscription != null) {

this.subscription.unsubscribe();

}

}

private Func1, Observable>> retryFunction = new Func1, Observable>>() {

@Override

public Observable> call(Observable extends Throwable> observable) {

return observable.flatMap(new Func1>() {

@Override

public Observable> call(final Throwable throwable) {

if (noInternetConnectionInterface!= null && (throwable instanceof IOException || throwable instanceof SocketTimeoutException)) {

return noInternetConnectionInterface.noInternetConnection(throwable);

}else{

return Observable.error(throwable);

}

}

});

}

}

SomeApiCallAction只是一个简单的类,它包含了内部的改进api调用,唯一特别的是它的重试功能.重试函数将检查throwable是否是IOException或SocketTimeoutException,如果是,它将调用接口,以便我们可以向用户提供重试对话框,询问他们是否要重试该操作.我们的用法类似于以下代码段

public class SomeActivity implement NoInternetConnectionInterface {

@OnClick(R.id.button)

public void do(View v) {

new SomeApiCallAction().execute(

new Subscriber(),

this

)

}

@Override

public PublishSubject noInternetConnection(final Throwable throwable) {

Log.i("Dev", Thread.currentThread() " Error!");

final PublishSubject subject = PublishSubject.create();

runOnUiThread(new Runnable() {

@Override

public void run() {

NoInternetDialogFragment dialog = NoInternetDialogFragment.newInstance();

dialog.setNoInternetDialogFragmentListener(new NoInternetDialogFragmentListener{

@Override

public void onUserChoice(boolean retry, NoInternetDialogFragment dialog) {

Log.i("Dev", Thread.currentThread() " Button Click!");

if (retry) {

subject.onNext(1);

} else {

subject.onError(throwable);

}

dialog.dismiss();

}

});

dialog.show(getSupportFragmentManager(), NoInternetDialogFragment.TAG);

}

});

return subject;

}

}

当我们使用Retrofit 1.9.0时,这个实现工作得非常完美.我们通过打开飞行模式进行测试,然后按下按钮执行api呼叫.

>第一次执行失败,我在重试功能中得到了UnknownHostException.

>所以,我调用界面(Activity)来显示重试对话框

>我仍然在飞行模式下按重试按钮重复执行

>正如预期的那样,用户按下重试按钮后发生的每次执行都失败了,我总是在重试功能中得到UnknownHostException.

>如果我一直按下重试按钮,重试对话框将永远显示,直到我关闭飞行模式.

但在我们更新我们的依赖关系之后

'com.squareup.retrofit2:retrofit:2.0.2'

'com.squareup.retrofit2:adapter-rxjava:2.0.2'

我们再试一次,但这次行为改变了,

>第一次执行失败,我在重试功能中获得了与之前相同的UnknownHostException.

>所以,我调用界面(Activity)来显示重试对话框

>我仍然在飞行模式下按重试按钮重复执行

>但是这一次,在重试函数中,我得到了NetworkOnMainThreadException而不是像它那样接收UnknowHostException.

>因此条件不匹配,接口没有被调用,结果只有1个重试对话框呈现给用户.

以下是上面代码的日志

Thread[android_0,5,main] Error!

Thread[main,5,main] Button Click!

你知道这会导致什么吗?任何建议,评论都会非常感激.

注意:以下是我们一直在使用并可能相关的其他依赖项.但是它们最近没有更新,从本项目开始就使用这些版本.

'com.jakewharton:butterknife:8.0.1'

'io.reactivex:rxandroid:1.1.0'

'io.reactivex:rxjava:1.1.0'

'com.google.dagger:dagger-compiler:2.0'

'com.google.dagger:dagger:2.0'

'javax.annotation:jsr250-api:1.0'

更多信息

我只是将我的代码重置回到我们使用Retrofit 1.9的时候,我发现打印日志不同

Thread[Retrofit-Idle,5,main] Error!

Thread[main,5,main] Button Click!

不确定这是否与问题有关,但很明显,在1.9.0中,我将不同线程中的接口调用为2.0.0

最终编辑

在阅读了@JohnWowUs的答案并按照他提供的链接后,我发现在Retrofit 2中,网络调用默认是同步的

要解决我的问题,有两种方法可以解决此问题

1.)按照@JohnWowUs的建议,通过为retryFunction指定线程

this.subscription = retrofit.someService().someApiCall()

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(subscriber)

.retryWhen(retryFunction, Schedulers.io());

2.)创建改造对象时,在创建RxJavaCallAdapterFactory时指定线程

retrofit = new Retrofit.Builder()

.baseUrl(AppConfig.BASE_URL)

.client(client)

.addConverterFactory(GsonConverterFactory.create(getGson()))

.addCallAdapterFactory(

RxJavaCallAdapterFactory.createWithScheduler(

Schedulers.from(threadExecutor)

)

)

.build();

解决方法:

我认为问题在于,当您重新订阅时,由于在retryWhen中使用默认的trampoline调度程序而在主线程上订阅. Retrofit 1.9为您处理了调度,因此使用subscribeOn毫无意义.问题讨论是here.在Retrofit 2中我相信这已经改变了所以你应该尝试类似的东西

this.subscription = retrofit.someService().someApiCall()

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(subscriber)

.retryWhen(retryFunction, Schedulers.io());

来源:https://www.icode9.com/content-4-275151.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,我可以为你生成一个关于Android RxJava + Retrofit + MVP网络框架封装的完整项目配置的博客。以下是一个示例: 标题:Android RxJava + Retrofit + MVP网络框架封装:完整项目配置 正文: 在Android开发,使用RxJava、Retrofit和MVP进行网络请求的框架封装是非常常见和实用的。本文将向你展示如何将它们结合起来,以实现一个完整的网络请求框架。 首先,确保你的Android项目已经引入了RxJava、Retrofit和MVP的相关依赖库。在项目的build.gradle文件添加以下依赖: ```groovy dependencies { // RxJava implementation 'io.reactivex.rxjava2:rxjava:2.2.21' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' // Retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0' // MVP implementation 'com.hannesdorfmann.mosby3:mvp:3.2.0' } ``` 接下来,我们将按照以下步骤完成完整的项目配置: 1. 创建网络请求接口 在你的项目创建一个接口,用于定义网络请求的方法。例如,创建一个名为ApiService的接口,其包含一个获取数据的方法。 ```java public interface ApiService { @GET("api/endpoint") Observable<ResponseData> getData(); } ``` 2. 创建网络请求管理类 创建一个名为ApiManager的类,用于管理网络请求。在这个类,你可以初始化Retrofit,并提供一个方法来执行具体的网络请求。 ```java public class ApiManager { private static final String BASE_URL = "http://your-api-base-url.com/"; private ApiService apiService; public ApiManager() { Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); apiService = retrofit.create(ApiService.class); } public Observable<ResponseData> getData() { return apiService.getData() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } } ``` 3. 创建Presenter层 在MVP架构,Presenter层负责处理业务逻辑和数据操作。创建一个名为MainPresenter的类,并在其调用ApiManager执行网络请求。 ```java public class MainPresenter { private MainView mainView; private ApiManager apiManager; public MainPresenter(MainView mainView) { this.mainView = mainView; apiManager = new ApiManager(); } public void fetchData() { apiManager.getData() .subscribe(new Observer<ResponseData>() { @Override public void onSubscribe(Disposable d) { // 可选的订阅回调 } @Override public void onNext(ResponseData responseData) { // 处理请求成功的数据 mainView.showData(responseData); } @Override public void onError(Throwable e) { // 处理请求失败的情况 mainView.showError(e.getMessage()); } @Override public void onComplete() { // 请求完成,可选的回调 } }); } } ``` 4. 创建View层 在MVP架构,View层负责展示数据和处理用户交互。创建一个名为MainActivity的类,并实现MainView接口。 ```java public class MainActivity extends AppCompatActivity implements MainView { private MainPresenter mainPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mainPresenter = new MainPresenter(this); mainPresenter.fetchData(); } @Override public void showData(ResponseData responseData) { // 展示数据到UI上 } @Override public void showError(String errorMessage) { // 展示错误信息到UI上 } } ``` 通过以上步骤,你就完成了Android使用RxJava、Retrofit和MVP进行网络请求的框架封装。根据你的实际需求,你可以进一步添加其他功能和模块来完善你的项目。 希望本文对你有所帮助!如果有任何疑问,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值