Retrofit Json data truncated - android

I am using Retrofit and RxAndroid to send GET request to server which is based on Django, and the server response with a JSON data.
The interesting thing i found is, with stetho, the last right brace of Json is lost. So i got this error msg:
W/System.err: java.io.EOFException: End of input at line 1 column 812 path $.user
W/System.err: at com.google.gson.stream.JsonReader.nextNonWhitespace(JsonReader.java:1393)
W/System.err: at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:482)
W/System.err: at com.google.gson.stream.JsonReader.hasNext(JsonReader.java:414)
W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:214)
W/System.err: at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37)
W/System.err: at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25)
W/System.err: at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:117)
W/System.err: at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:211)
W/System.err: at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
W/System.err: at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$RequestArbiter.request(RxJavaCallAdapterFactory.java:171)
W/System.err: at rx.Subscriber.setProducer(Subscriber.java:211)
W/System.err: at rx.internal.operators.OnSubscribeMap$MapSubscriber.setProducer(OnSubscribeMap.java:102)
W/System.err: at rx.Subscriber.setProducer(Subscriber.java:205)
W/System.err: at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:152)
W/System.err: at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:138)
W/System.err: at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
W/System.err: at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
W/System.err: at rx.Observable.unsafeSubscribe(Observable.java:10142)
W/System.err: at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
W/System.err: at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
W/System.err: at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
W/System.err: at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
W/System.err: at rx.Observable.unsafeSubscribe(Observable.java:10142)
W/System.err: at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
W/System.err: at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
W/System.err: at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
W/System.err: at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
W/System.err: at rx.Observable.unsafeSubscribe(Observable.java:10142)
W/System.err: at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)
W/System.err: at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
W/System.err: at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
W/System.err: at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
W/System.err: at java.lang.Thread.run(Thread.java:764)
Here is the json data from stetho:
{"id":47,"credit_card":"","order_ordereditem_set":[{"id":36,"product_item":{"id":3,"category":{"id":1,"name":"Fruit"},"added_time":"2018-02-11 15:23:21","upc":"4321","desc":"Mandarin","price":150,"img_url":"http://15.32.134.74:8000/media/images/products/mandarin.jpg","not_sale":false,"is_hot":false,"is_recommended":false},"added_time":"2018-02-12 14:02:11","quantity":1,"order_id":47},{"id":37,"product_item":{"id":2,"category":{"id":1,"name":"Fruit"},"added_time":"2018-02-08 13:29:07","upc":"123456","desc":"Kiwi","price":500,"img_url":"http://15.32.134.74:8000/media/images/products/kiwi.jpg","not_sale":false,"is_hot":true,"is_recommended":false},"added_time":"2018-02-12 14:02:11","quantity":1,"order_id":47}],"added_time":"2018-02-12 14:02:11","payment":"0","total_quantity":2,"total_price":6.5,"user":1
But i checked wireshark, there is no missing of right brace.
I also used postman, but there is no problem.
This issue comes out 30%.
Following is my code details:
private HttpUtil() {
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.create();
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(getOkHttpClient())
.baseUrl(SERVER_BASE_URL)
.build();
mService = retrofit.create(RestAPIService.class);
}
static public HttpUtil getHttpUtilInstance() {
if (mHttpUtil == null) {
synchronized (HttpUtil.class) {
mHttpUtil = new HttpUtil();
}
}
return mHttpUtil;
}
public RestAPIService getService() {
return mService;
}
private OkHttpClient getOkHttpClient() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
if (GlobalConfig.CONFIG_DEBUG)
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
else
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
OkHttpClient.Builder httpClientBuilder = new OkHttpClient
.Builder();
httpClientBuilder.addInterceptor(loggingInterceptor)
.addInterceptor(mTokenInterceptor)
.addNetworkInterceptor(new StethoInterceptor());
//httpClientBuilder.addNetworkInterceptor(loggingInterceptor);
return httpClientBuilder.build();
}
private boolean shouldAddToken(String url) {
return !url.contains("api/login");
}
private boolean alreadyHasAuthorizationHeader(Request request) {
return request.header("Authorization") != null;
}
// Interceptor used for inserting token into Header
private Interceptor mTokenInterceptor = new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request;
Request originalRequest = chain.request();
//request = originalRequest.newBuilder().addHeader("Connection", "close").build();
request = originalRequest;
String token = UserDataRepository.getInstance().getToken();
if (token == null || token.length() == 0 || alreadyHasAuthorizationHeader(originalRequest)) {
return chain.proceed(originalRequest);
}
if (shouldAddToken(originalRequest.url().toString())) {
request = request.newBuilder()
.header("Authorization", "JWT " + token)
.build();
}
return chain.proceed(request);
}
};
#Headers({"Content-Type: application/json", "Accept: application/json"})
#GET("api/order")
Observable<List<Order>> getOrder();

it's a bit late for the answer, but if someone has the same problem, I'll tell you how I solved it.
I was having the same error, the last character of the response was missing, but when testing the api with postman everything was fine, so I try the same code with other apis and it works.
The problem is the server, I was using laravel server so I installed and configured apache and the problem is solved.

Related

Deferred retrofit request response problem

I want to do an async-await to my Retrofit request.
#GET("{companyId}/{filename}")
#Streaming
suspend fun getFilePart(
#Path(value = "companyId") companyId: Int,
#Path(value = "filename") filename: String,
#QueryMap queryMap: Map<String, String>
): Deferred<ResponseBody>
and when i call it from a CoroutineScope i have
val deferredList = pendingFiles.map {
async(Dispatchers.IO) {
try {
// runs in parallel in background thread
// Consider i have the data parameters....
apiManager.mApiService(base).getFilePart(it.companyId, fileName, urlQueryMap)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
So the request returns 200 which means that it is successful, and i see the Logging with the File part data. But i get the following exception
W/System.err: java.lang.RuntimeException: Unable to invoke no-args constructor for com.google.firebase.inject.Deferred<okhttp3.ResponseBody>. Registering an InstanceCreator with Gson for this type may fix this problem.
W/System.err: at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:228)
W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212)
W/System.err: at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:40)
W/System.err: at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
W/System.err: at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
W/System.err: at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:153)
W/System.err: at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:520)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err: at java.lang.Thread.run(Thread.java:920)
W/System.err: Caused by: java.lang.UnsupportedOperationException: Interface can't be instantiated! Interface name: com.google.firebase.inject.Deferred
W/System.err: at com.google.gson.internal.UnsafeAllocator.assertInstantiable(UnsafeAllocator.java:117)
W/System.err: at com.google.gson.internal.UnsafeAllocator$1.newInstance(UnsafeAllocator.java:49)
W/System.err: at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:225)
W/System.err: ... 9 more
If your function is suspend, it shouldn't return Deferred. Just declare it this way:
#GET("{companyId}/{filename}")
#Streaming
suspend fun getFilePart(
#Path(value = "companyId") companyId: Int,
#Path(value = "filename") filename: String,
#QueryMap queryMap: Map<String, String>
): ResponseBody // no Deferred here
Functions with suspend keyword are used like regular functions (that's the beauty of coroutines), so they return a regular type. You actually start asynchronous code when you use coroutine builders like you do with async - this is the one that returns Deferred<T> and is not suspending.

Retrofit 2.3 Handling SocketTimeoutException

I'm currently using Retrofit 2.3 and RxAndroid for Android as my network communications. Its working fine most of the time. But sometimes, I get a SocketTimeOut exception (I'm assuming due to issues with the internet). I want to be able to handle this case but, putting a try catch around my retrofit calls in my activity doesn't catch this. Likewise, it doesn't go to the OnError method either (I don't see an option for an OnFailure method). The exception, instead, is shown in my RetrofitHelper class, at the return statement of the intercept method. Here is my Retrofit helper class:
public class RetrofitHelper {
/**
* The APICalls communicates with the json api of the API provider.
*/
public APICalls getAPICalls() {
final Retrofit retrofit = createRetrofit();
return retrofit.create(APICalls.class);
}
/**
* This custom client will append the "username=demo" query after every request.
*/
private OkHttpClient createOkHttpClient() {
final OkHttpClient.Builder httpClient =
new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
final Request original = chain.request();
final HttpUrl originalHttpUrl = original.url();
final HttpUrl url = originalHttpUrl.newBuilder()
.build();
// Request customization: add request headers
final Request.Builder requestBuilder = original.newBuilder()
.url(url);
final Request request = requestBuilder.build();
return chain.proceed(request);
}
});
return httpClient.build();
}
/**
* Creates a pre configured Retrofit instance
*/
private Retrofit createRetrofit() {
return new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create()) // Library for parsing json responses
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // Library for easier threading/background processing
.client(createOkHttpClient())
.build();
}
}
And here is my interface for my API calls
public interface APICalls {
#GET("Vehicle/VehiclePositions.json")
Single<ResponseVehiclePosition> getVehiclePositions();
#GET("TripUpdate/TripUpdates.json")
Single<ResponseTripUpdate> getTripUpdates();
}
And here is the log:
2020-06-05 15:43:34.877 10007-10007/com.samramakrishnan.campusbustracker E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.samramakrishnan.campusbustracker, PID: 10007
java.net.SocketTimeoutException: failed to connect to transitdata.cityofmadison.com/204.147.0.120 (port 80) from /10.0.2.16 (port 35902) after 10000ms
at libcore.io.IoBridge.connectErrno(IoBridge.java:191)
at libcore.io.IoBridge.connect(IoBridge.java:135)
at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
at java.net.Socket.connect(Socket.java:621)
at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:63)
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:223)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:149)
at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:192)
at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)
at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)
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:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at com.samramakrishnan.campusbustracker.restapi.RetrofitHelper$1.intercept(RetrofitHelper.java:55)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)
at okhttp3.RealCall.execute(RealCall.java:69)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:180)
at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:41)
at io.reactivex.Observable.subscribe(Observable.java:10179)
at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)
at io.reactivex.Observable.subscribe(Observable.java:10179)
at io.reactivex.internal.operators.observable.ObservableSingleSingle.subscribeActual(ObservableSingleSingle.java:35)
at io.reactivex.Single.subscribe(Single.java:2558)
at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
at io.reactivex.Scheduler$1.run(Scheduler.java:134)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
I think you are able to catch the exception by the BiConsumer in the subscribe method when you call do the GET call.
According to the source file:
public final Disposable subscribe(final Consumer<? super T> onSuccess, final Consumer<? super Throwable> onError)
so I think you can do something like:
compositeDisopsable.add(getAPICalls().getVehiclePositions()
.subscribeOn(...)
...
.subscribe( response -> {
//do what you want to do with the `response`
}, throwable -> {
if(throwable instanceOf SocketTimeoutException){
//handle your exception
});

certificatePinner not working with okhttp throwing SSLHandshakeException: CertPathValidatorException Trust anchor for certification path not found

I've taken the code from Square's own github Readme:
#Throws(Exception::class)
fun run() {
val client = OkHttpClient.Builder()
.certificatePinner(CertificatePinner.Builder()
.add("api.somewebsite.nl", "sha256/SOME_KEY/SOME_KEY")
.build())
.build()
val request = Request.Builder()
.url("https://api.somewebsite.nl")
.build()
try {
val response = client.newCall(request).execute()
if (!response.isSuccessful) {
Log.i("TestCode","is Not Successful")
throw IOException("Unexpected code $response")
} else {
Log.i("TestCode","is Successful")
}
for (certificate in response.handshake()!!.peerCertificates()) {
println(CertificatePinner.pin(certificate))
}
} catch (e: SSLHandshakeException) {
e.printStackTrace()
}
}
When going to this website using Chrome it works, indicating that the App has the Comodo CA certificate on the particular phone. For the SHA256 pin value I went to this site. This site is also mentioned in this excellent walkthrough.
I've used the latest versions of the libraries:
implementation "com.squareup.retrofit2:retrofit:2.5.0"
implementation "com.squareup.retrofit2:converter-moshi:2.5.0"
implementation "com.squareup.okhttp3:okhttp:3.14.1"
Here is the Logging:
E/Conscrypt: ------------------Untrusted chain: ----------------------
E/Conscrypt: == Chain0 ==
Version: 3
E/Conscrypt: Serial Number: serial_number
E/Conscrypt: SubjectDN: CN=*.somewebsite.nl, OU=PremiumSSL Wildcard, OU=IT, O=somewebsite B.V., STREET=some_street, L=SomeCity, ST=SomeCity, OID.2.5.4.17=POSTAL_CODE, C=NL
E/Conscrypt: IssuerDN: CN=Sectigo RSA Organization Validation Secure Server CA, O=Sectigo Limited, L=Salford, ST=Greater Manchester, C=GB
E/Conscrypt: Get not before: Mon May 06 02:00:00 GMT+02:00 2019
E/Conscrypt: Get not after: Mon Jul 05 01:59:59 GMT+02:00 2021
E/Conscrypt: Sig ALG name: SHA256withRSA
E/Conscrypt: Signature: SOME_SIGNATURE
E/Conscrypt: Public key:
W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
W/System.err: at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:361)
W/System.err: at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:336)
W/System.err: at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:300)
W/System.err: at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:185)
W/System.err: at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
W/System.err: at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:107)
W/System.err: at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:87)
W/System.err: at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)
W/System.err: at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
W/System.err: at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
W/System.err: at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
W/System.err: at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
W/System.err: at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:221)
W/System.err: at okhttp3.RealCall.execute(RealCall.java:81)
Try to Modify OkHttpClient.Builder Object: see this solution

Fatal Exception: java.io.InterruptedIOException: thread interrupted while using retrofit with rxjava

I am getting this random exception that crashes my app while making network calls with retrofit and am looking for some guidance for resolution
Fatal Exception: java.io.InterruptedIOException: thread interrupted
at okio.Timeout.throwIfReached(Timeout.java:145)
at okio.Okio$1.write(Okio.java:76)
at okio.AsyncTimeout$1.write(AsyncTimeout.java:180)
at okio.RealBufferedSink.flush(RealBufferedSink.java:216)
at okhttp3.internal.http2.Http2Writer.flush(Http2Writer.java:121)
at okhttp3.internal.http2.Http2Connection.newStream(Http2Connection.java:239)
at okhttp3.internal.http2.Http2Connection.newStream(Http2Connection.java:205)
at okhttp3.internal.http2.Http2Codec.writeRequestHeaders(Http2Codec.java:111)
at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:50)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at com.happycorp.happy.happyapp.util.Network$1.intercept(Network.java:80)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at com.happycorp.android.commondata.net.RetrofitFactory$CustomHttpMetricsLogger.intercept(RetrofitFactory.java:139)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:125)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at com.happycorp.android.commondata.net.RetrofitFactory$1.intercept(RetrofitFactory.java:83)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:212)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
at okhttp3.RealCall.execute(RealCall.java:77)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:180)
at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:41)
at io.reactivex.Observable.subscribe(Observable.java:10179)
at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)
at io.reactivex.Observable.subscribe(Observable.java:10179)
at io.reactivex.internal.operators.observable.ObservableSingleSingle.subscribeActual(ObservableSingleSingle.java:35)
at io.reactivex.Single.subscribe(Single.java:2558)
at io.reactivex.internal.operators.single.SingleToFlowable.subscribeActual(SingleToFlowable.java:37)
at io.reactivex.Flowable.subscribe(Flowable.java:12218)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:156)
at io.reactivex.internal.operators.flowable.FlowableFromIterable$IteratorSubscription.slowPath(FlowableFromIterable.java:238)
at io.reactivex.internal.operators.flowable.FlowableFromIterable$BaseRangeSubscription.request(FlowableFromIterable.java:123)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onSubscribe(FlowableFlatMap.java:110)
at io.reactivex.internal.operators.flowable.FlowableFromIterable.subscribe(FlowableFromIterable.java:68)
at io.reactivex.internal.operators.flowable.FlowableFromIterable.subscribeActual(FlowableFromIterable.java:46)
at io.reactivex.Flowable.subscribe(Flowable.java:12218)
at io.reactivex.internal.operators.flowable.FlowableFlatMap.subscribeActual(FlowableFlatMap.java:52)
at io.reactivex.Flowable.subscribe(Flowable.java:12218)
at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
This is what the service interface looks like:
#GET("categories")
Single<Category> getCategories();
#GET("categories/{categoryId}")
Single<Category> getCategory(#Path("categoryId") Integer id);
#GET("categories")
Single<Category> getCategoriesByRootCategory(#Query("rootCategoryId") Integer id);
#GET("products")
Single<ProductSearchResult> getProductsBySingleFilter(#Query(SINGLE_FILTER_BASE + "[field]")
String searchCriteria,
#Query(SINGLE_FILTER_BASE + "[conditionType]")
String conditionType,
#Query(SINGLE_FILTER_BASE + "[value]") String value);
Here is the code that creates the okhttp client and the retrofit interface:
public static OkHttpClient getOkHttpClient(#Nullable final File parentCacheDir,
#NonNull final AuthProvider authProvider,
#NonNull final ApiEnvironment apiEnvironment,
#Nullable final Interceptor cacheInterceptor) {
Cache cache = null;
if (parentCacheDir != null) {
File responseCacheDirectory = new File(parentCacheDir, RESPONSE_CACHE_DIRECTORY);
cache = new Cache(responseCacheDirectory, CACHE_SIZE);
}
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(NETWORK_REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.readTimeout(NETWORK_REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.writeTimeout(NETWORK_REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.cache(cache);
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
builder.addInterceptor(loggingInterceptor);
builder.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request.Builder requestBuilder = chain.request().newBuilder();
requestBuilder.header(KEY_CONTENT_TYPE, APPLICATION_JSON);
requestBuilder = addAuthHeaders(requestBuilder, apiEnvironment);
if (apiEnvironment.getDefaultRequestParams() != null) {
requestBuilder = addDefaultParams(requestBuilder, apiEnvironment);
}
return chain.proceed(requestBuilder.build());
}
});
builder.addNetworkInterceptor(new CustomHttpMetricsLogger());
if (cacheInterceptor != null) {
builder.addNetworkInterceptor(cacheInterceptor);
}
return builder.build();
}
public static Retrofit newInstance(#NonNull final AuthProvider authProvider,
#NonNull final ApiEnvironment apiEnvironment,
#Nullable final File parentCacheDir,
#Nullable final Interceptor debugInterceptor) {
return new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(getGson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(getOkHttpClient(parentCacheDir, authProvider, apiEnvironment, debugInterceptor))
.baseUrl(apiEnvironment.getBaseUrl())
.build();
}
And here is the code that is generating the exception:
public static Flowable<ProductSearchResult> getAllItemsForCategories(final HebMagentoApi magentoService,
List<Category> categories) {
return Flowable.fromIterable(categories).flatMap(category ->
magentoService.getProductsBySingleFilter(HebMagentoApi.MAGENTO_CATEGORY_ID,
HebMagentoApi.MAGENTO_FILTER_EQUAL,
String.valueOf(category.getId())).toFlowable());
}
I think this issue is related to this line in the adapter code:
https://github.com/square/retrofit/blob/master/retrofit-adapters/rxjava2/src/main/java/retrofit2/adapter/rxjava2/BodyObservable.java#L59
The issue was with how we are creating the RxJava2CallAdapterFactory. We were using Dagger 2 to create the okhttp client and as far as I know that graph was constructed on the main thread and so the rxjava2calladapterfactory would use the main thread by default if we were creating flowables / observables by hand using retrofit.
To fix this so that all of the calls to Retrofit using RxJava2 happen on a background thread we create the call adapter in the the following way:
RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io())
IMPORTANT: The other thing to check to keep your app from crashing is to make sure that you are defining onError functions for each of your RxJava operators: flatMap, map, etc

Rxjava + Retrofit Throwing OutOfMemoryError

When I use Retrofit with rxjava, some machine throwing OOM, this is log:
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:818)
Caused by: java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:1063)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:920)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1338)
at okhttp3.ConnectionPool.put(ConnectionPool.java:135)
at okhttp3.OkHttpClient$1.put(OkHttpClient.java:149)
at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:188)
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)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:124)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:145)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:170)
at okhttp3.RealCall.execute(RealCall.java:60)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$RequestArbiter.request(RxJavaCallAdapterFactory.java:171)
at rx.internal.operators.OperatorSubscribeOn$1$1$1.request(OperatorSubscribeOn.java:80)
at rx.Subscriber.setProducer(Subscriber.java:209)
at rx.internal.operators.OperatorSubscribeOn$1$1.setProducer(OperatorSubscribeOn.java:76)
at rx.Subscriber.setProducer(Subscriber.java:205)
at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:152)
at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:138)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
at rx.Observable.unsafeSubscribe(Observable.java:9861)
at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)
at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:221)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
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:818)
my retrofit code:
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
if (BuildConfig.LOG_DEBUG)
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
else
interceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.retryOnConnectionFailure(true)
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(ConstantValue.URL + "/")
.client(client)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
and my request code:
public interface GetUserFriendUsersService {
#FormUrlEncoded
#POST("IM/GetUserFriendUsers")
Observable<ResponseBody> getUserFriendUsers(#Field("UserID")String UserID);}
public void getUserFriendUsers(String userID, Subscriber<List<Users>> subscriber) {
retrofit.create(GetUserFriendUsersService.class)
.getUserFriendUsers(userID)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.map(new HttpResultFunc())
.map(new Func1<JSONObject, List<Users>>() {
#Override
public List<Users> call(JSONObject jsonObject) {
List<Users> users = JSON.parseArray(jsonObject.getString("users"), Users.class);
if (users.size() == 0)
throw new CustomizeException("no data");
return users;
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
The .observeOn() should be in front of map(),and in back of unsubscribeOn()
Posted the same question at RxAndroid github.
The problem is that Schedulers.io() uses a cached thread pool without a limit and thus is trying to create 1500 threads. You should consider using a Scheduler that has a fixed limit of threads, or using RxJava 2.x's parallel() operator to parallelize the operation to a fixed number of workers.
If you're using raw Retrofit by default it uses OkHttp's dispatcher which limits the threads to something like 64 (with a max of 5 per host). That's why you aren't seeing it fail.
If you use createAsync() when creating the RxJava2CallAdapterFactory it will create fully-async Observable instances that don't require a subscribeOn and which use OkHttp's Dispatcher just like Retrofit would otherwise. Then you only need observeOn to move back to the main thread, and you avoid all additional thread creation.

Categories

Resources