Retrofit + rxandroid导致kitkat上的stackoverflow错误

时间:2016-11-05 18:51:56

标签: android retrofit2 rx-android

我正在使用Retrofit 2 + RxAndroid,这个代码在Marshmallow和Lollipop设备上运行很好,但是没有使用kitkat设备。

@OnClick(R.id.login_btn)
public void onLoginClicked() {
    loginBtn.setEnabled(false);
    AuthenticationAPI authApi = ServiceCreator.createService(AuthenticationAPI.class, null);
    authApi.login(new LoginUserRequest(emailEditText.getText().toString(), passwordEditText.getText().toString()))
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(verifyEmailResponse -> Log.i("TEST", "onNext: " + verifyEmailResponse.success),
             throwable -> {
             handleError(throwable);
             loginBtn.setEnabled(true);
             });
}

ServiceCreator.java

public class ServiceCreator {

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
    private static final int DEFAULT_TIMEOUT = 30; //seconds

    private static Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create();
    private static RxJavaCallAdapterFactory rxAdapter = RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io());

    private static Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl(BuildConfig.REST_BASE_ENDPOINT)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(rxAdapter);

    public static <RESTService> RESTService createService(Class<RESTService> service, String userToken) {

        if (BuildConfig.REST_DEBUG) {
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            httpClient.addInterceptor(logging);
        }

        if (StringUtils.isNotBlank(userToken)) {
            httpClient.addInterceptor(chain -> {
                Request original = chain.request();

                Request request = original.newBuilder()
                        .header(Constants.AUTHORIZATION_HEADER, userToken)
                        .method(original.method(), original.body())
                        .build();
                return chain.proceed(request);
            });
        }

        httpClient.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        httpClient.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        httpClient.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        Retrofit retrofit = builder.client(httpClient.build()).build();
        return retrofit.create(service);
    }

    public static Retrofit retrofit() {
        return builder.client(httpClient.build()).build();
    }
}

错误:

FATAL EXCEPTION: RxNewThreadScheduler-1 java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
   at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:59)
   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
   at java.util.concurrent.FutureTask.run(FutureTask.java:237)
   at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
   at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
   at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.StackOverflowError
   at org.apache.harmony.security.asn1.ASN1StringType.getDecodedObject(ASN1StringType.java:99)
   at org.apache.harmony.security.asn1.ASN1StringType.decode(ASN1StringType.java:90)
   at org.apache.harmony.security.asn1.ASN1Choice.decode(ASN1Choice.java:308)
   at org.apache.harmony.security.x501.AttributeTypeAndValue$1.decode(AttributeTypeAndValue.java:339)
   at org.apache.harmony.security.asn1.BerInputStream.readSequence(BerInputStream.java:554)
   at org.apache.harmony.security.asn1.DerInputStream.readSequence(DerInputStream.java:105)
   at org.apache.harmony.security.asn1.ASN1Sequence.decode(ASN1Sequence.java:40)
   at org.apache.harmony.security.asn1.BerInputStream.decodeValueCollection(BerInputStream.java:626)
   at org.apache.harmony.security.asn1.BerInputStream.readSetOf(BerInputStream.java:606)
   at org.apache.harmony.security.asn1.DerInputStream.readSetOf(DerInputStream.java:115)
   at org.apache.harmony.security.asn1.ASN1SetOf.decode(ASN1SetOf.java:40)
   at org.apache.harmony.security.asn1.BerInputStream.decodeValueCollection(BerInputStream.java:626)
   at org.apache.harmony.security.asn1.BerInputStream.readSequenceOf(BerInputStream.java:584)
   at org.apache.harmony.security.asn1.ASN1SequenceOf.decode(ASN1SequenceOf.java:40)
   at org.apache.harmony.security.asn1.ASN1Type.decode(ASN1Type.java:82)
   at javax.security.auth.x500.X500Principal.<init>(X500Principal.java:78)
   at com.android.org.conscrypt.OpenSSLX509Certificate.getIssuerX500Principal(OpenSSLX509Certificate.java:422)
   at com.android.org.conscrypt.OpenSSLX509Certificate.getIssuerDN(OpenSSLX509Certificate.java:236)
   at com.android.org.conscrypt.TrustManagerImpl.cleanupCertChainAndFindTrustAnchors(TrustManagerImpl.java:340)
   at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:225)
   at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:202)
   at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:611)
   at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
   at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
   at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:241)
   at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:198)
   at okhttp3.internal.connection.RealConnection.buildConnection(RealConnection.java:174)
   at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:114)
   at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:193)
   at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:129)
   at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:98)
   at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
   at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
   at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
   at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:109)
   at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)

谢谢!

//更新:我发现了导致错误的原因而不是解决方案,我在https://github.com/square/okhttp/issues/2962中创建了一个问题

2 个答案:

答案 0 :(得分:1)

发生错误是因为我一遍又一遍地添加相同的拦截器,新版本可能是。

public class ServiceCreator {

    private OkHttpClient.Builder httpClient;
    private static final int DEFAULT_TIMEOUT = 30; //seconds

    private Gson gson;
    private RxJavaCallAdapterFactory rxAdapter;
    private Retrofit.Builder builder;

    private static ServiceCreator mInstance = null;

    private ServiceCreator() {
        httpClient = new OkHttpClient.Builder();
        gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create();
        rxAdapter = RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io());
        builder = new Retrofit.Builder()
                .baseUrl(BuildConfig.REST_BASE_ENDPOINT)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(rxAdapter);

        if (BuildConfig.REST_DEBUG) {
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            httpClient.addInterceptor(logging);
        }
    }

    public static ServiceCreator getInstance() {
        if (mInstance == null) {
            mInstance = new ServiceCreator();
        }
        return mInstance;
    }

    public <RESTService> RESTService createService(Class<RESTService> service, String userToken) {

        if (StringUtils.isNotBlank(userToken)) {
            httpClient.addInterceptor(chain -> {
                Request original = chain.request();

                Request request = original.newBuilder()
                        .header(Constants.AUTHORIZATION_HEADER, userToken)
                        .method(original.method(), original.body())
                        .build();
                return chain.proceed(request);
            });
        }

        httpClient.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        httpClient.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        httpClient.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        Retrofit retrofit = builder.client(httpClient.build()).build();
        return retrofit.create(service);
    }

    public Retrofit retrofit() {
        return getInstance().builder.client(getInstance().httpClient.build()).build();
    }
}

答案 1 :(得分:0)

这是处理OkHttp和改造的最微不足道的问题之一。实际上,我也在努力争取解决方案很长一段时间,直到我因为下面的代码块而导致错误。

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(logging);

因此,一旦删除了线条,就应该正常工作。