square / retrofit

A type-safe HTTP client for Android and the JVM
https://square.github.io/retrofit/
Apache License 2.0
43.15k stars 7.3k forks source link

The exception of mergeDelayError in Rxjava and Retrofit #2821

Open MoMask opened 6 years ago

MoMask commented 6 years ago

I encountered this requirement. In an activity, I need to request four network interfaces. In order to facilitate the use, the mergeDelayError operation of Rxjava conforms to a request, but the actual situation is that when one of the requests is wrong, it will cause Retrofit to trigger. RxJavaCallAdapterFactory this class. This caused the subscription to be cancelled, which prevented me from requesting requests from other networks.

JakeWharton commented 6 years ago

Are you saying there's a bug? If so, could you please provide a self-contained code snippet that demonstrates the behavior?

Otherwise Retrofit makes a request when you subscribe and cancels when you unsubscribe which is pretty standard as far as Rx goes...

MoMask commented 6 years ago

There are four such network requests in my needs, they need to be requested together in one page. But with the resulting callbacks that have successfully requested four requests, there have been four callbacks that failed, which is not friendly to the interface. I think the operators in Rxjava can solve this problem, so I tried to use it like this.

   public Subscription getHallPageData(Subscriber subscriber) {

        Observable<List<BannerBean>> banner = RetrofitHelper
                .getService(IActivityService.class)
                .getBanner()
                .map(new HttpResultFunc<List<BannerBean>>());

        Observable<List<Bulletin>> bulletin = RetrofitHelper
                .getService(IActivityService.class)
                .getBulletin()
                .map(new HttpResultFunc<List<Bulletin>>());

        Observable<HotLotteryBean> home = RetrofitHelper
                .getService(ILotteryService.class)
                .getHomeLottery()
                .map(new HttpResultFunc<>());

        Observable<AllMode> all = RetrofitHelper
                .getService(ILotteryService.class)
                .getAllLottery()
                .map(new HttpResultFunc<>());

        Observable<Object> merge = Observable.mergeDelayError(banner, bulletin, home, all);

        return toSubscribe(merge, subscriber);
    }

This use seems to be no problem. In the test environment, I can get the data of four interfaces through one subscription, and only two callbacks, the code becomes simple. However, this is not the case in a formal environment. When one of the four network interface data has a problem, the subscription will be cancelled in advance and the remaining network interfaces cannot be requested. like this. .

07-10 10:11:06.495 11229-11291/? D/OkHttp: --> POST http://103.100.62.125:8383/mobile/banner.html
    Content-Length: 0
    Host: wanjiba.net
    User-Agent: app_android
    VersionName: 1.0.0
    SysCode: 5.1.1
    Brand: OPPO
    Model: A37fw
    serialNo: 05965c077ce1ba2e061e0c1097b92d2a
    Cookie: SID=Rc0rXjeniIPsXml9A7yn4o+sg32Y2N4A9O3LM7evvPjDZtxuJt7aAJD1PIhEkH+0WzkcFHBp+euxlgHAjF1pCQjRu8p+0X7cuB5VinXwORY=; Path=/; HttpOnly
    --> END POST (0-byte body)
07-10 10:11:06.595 11229-11291/? D/OkHttp: <-- 200 OK http://103.100.62.125:8383/mobile/banner.html (97ms)
    Server: openresty
    Date: Tue, 10 Jul 2018 02:11:06 GMT
    Content-Type: text/html;charset=utf-8
    Transfer-Encoding: chunked
    Connection: keep-alive
    Vary: Accept-Encoding
    Set-Cookie: route=e4d72e5932637c415a9cacdfc2d328b2; Path=/
    Content-Disposition: inline;filename=f.txt
    uuid: 0111d8e26ecc3fffe8cfc37fdd4f0112
    {"error":0,"data":[]}
    <-- END HTTP (21-byte body)
    --> POST http://103.100.62.125:8383/mobile/bulletin.html
    Content-Length: 0
    Host: wanjiba.net
    User-Agent: app_android
    VersionName: 1.0.0
    SysCode: 5.1.1
    Brand: OPPO
    Model: A37fw
    serialNo: 05965c077ce1ba2e061e0c1097b92d2a
    Cookie: SID=Rc0rXjeniIPsXml9A7yn4o+sg32Y2N4A9O3LM7evvPjDZtxuJt7aAJD1PIhEkH+0WzkcFHBp+euxlgHAjF1pCQjRu8p+0X7cuB5VinXwORY=; Path=/; HttpOnly
    --> END POST (0-byte body)
    <-- HTTP FAILED: java.io.IOException: Canceled
swankjesse commented 6 years ago

Unclear what action we should take on this. Can you provide a failing test case?

Sergioct commented 6 years ago

Same error here retrofit 2.4 and rxjava 2.2.0

alibeheshtian commented 6 years ago

Same error here retrofit 2.5 and rxjava 2.2.3

and

ProGuard

`-keepattributes Signature, InnerClasses, EnclosingMethod

Retain service method parameters when optimizing. -keepclassmembers,allowshrinking,allowobfuscation interface { @retrofit2.http. ; }`

everything in debug work!! not work in release variant ....

Data Model

data class TokenModel(val access_token: String, val refresh_token: String)

Api Interface

@POST("oauth/token?vas_id=1") fun login(@Body parameters: Map<String,String>) : Single<TokenModel>

retrofit cannot map to model