2

I'm fetching JSON data from the web via GET request. The code is the following, even though the problems seems to be "conceptual".

/**
 * Make an HTTP request to the given URL and return a String as the response.
 */
public static String makeHttpRequest(URL url) throws IOException {
    String jsonResponse = "";

    //Check that url is not null
    if(url == null){
        return jsonResponse;
    }

    HttpURLConnection urlConnection = null;
    InputStream inputStream = null;
    try {
        urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("GET");
      urlConnection.setReadTimeout(10000 /* milliseconds */);
           urlConnection.setConnectTimeout(15000 /* milliseconds */);
         urlConnection.connect();

        //If the request was successfull (code 200)
        //then read the imput string and parse the response
        if(urlConnection.getResponseCode() == 200) {
            inputStream = urlConnection.getInputStream();
            jsonResponse = readFromStream(inputStream);
        }
        else {
            Log.e(LOG_TAG_MAIN, "Error Response code" + urlConnection.getResponseCode());
        }

    } catch (IOException e) {
        Log.e(LOG_TAG_MAIN, "Problem the JSON results", e);
    } finally {
        if (urlConnection != null) {
            urlConnection.disconnect();
        }
        if (inputStream != null) {
            // Closing the input stream could throw an IOException, which is why
            // the makeHttpRequest(URL url) method signature specifies than an IOException
            // could be thrown.
            inputStream.close();
        }
    }
    return jsonResponse;
}
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
/**
 * Convert the {@link InputStream} into a String which contains the
 * whole JSON response from the server.
 */
public static String readFromStream(InputStream inputStream) throws IOException {
    StringBuilder output = new StringBuilder();
    if (inputStream != null) {
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
        BufferedReader reader = new BufferedReader(inputStreamReader);
        String line = reader.readLine();
        while (line != null) {
            output.append(line);
            line = reader.readLine();
        }
    }
    return output.toString();
}

Indeed the following code worked for months, but suddenly started throwing:

E/com.example.android.abcfolio.MainActivity: Problem the JSON results
                                             java.net.SocketTimeoutException: timeout
 at com.android.okhttp.okio.Okio$3.newTimeoutException(Okio.java:207)
 at com.android.okhttp.okio.AsyncTimeout.exit(AsyncTimeout.java:250)
 at com.android.okhttp.okio.AsyncTimeout$2.read(AsyncTimeout.java:217)
 at com.android.okhttp.okio.RealBufferedSource.request(RealBufferedSource.java:71)
 at com.android.okhttp.okio.RealBufferedSource.require(RealBufferedSource.java:64)
 at com.android.okhttp.okio.RealBufferedSource.readHexadecimalUnsignedLong(RealBufferedSource.java:270)
 at com.android.okhttp.internal.http.HttpConnection$ChunkedSource.readChunkSize(HttpConnection.java:479)
 at com.android.okhttp.internal.http.HttpConnection$ChunkedSource.read(HttpConnection.java:460)
 at com.android.okhttp.okio.RealBufferedSource.read(RealBufferedSource.java:50)
 at com.android.okhttp.okio.RealBufferedSource.exhausted(RealBufferedSource.java:60)
 at com.android.okhttp.okio.InflaterSource.refill(InflaterSource.java:101)
 at com.android.okhttp.okio.InflaterSource.read(InflaterSource.java:62)
 at com.android.okhttp.okio.GzipSource.read(GzipSource.java:80)
 at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:349)
 at java.io.InputStreamReader.read(InputStreamReader.java:233)
 at java.io.BufferedReader.fillBuf(BufferedReader.java:145)
 at java.io.BufferedReader.readLine(BufferedReader.java:397)
 at com.example.android.abcfolio.utils.NetworkCommonUtils.readFromStream(NetworkCommonUtils.java:102)
 at com.example.android.abcfolio.utils.NetworkCommonUtils.makeHttpRequest(NetworkCommonUtils.java:68)
 at com.example.android.abcfolio.utils.NetworkCoinMarketCapUtils.fetchCoinMarketCapData(NetworkCoinMarketCapUtils.java:44)
 at com.example.android.abcfolio.sync.CoinsSyncTask.syncCoins(CoinsSyncTask.java:65)
 at com.example.android.abcfolio.sync.CoinsFirebaseJobService$1.doInBackground(CoinsFirebaseJobService.java:64)
 at com.example.android.abcfolio.sync.CoinsFirebaseJobService$1.doInBackground(CoinsFirebaseJobService.java:53)
 at android.os.AsyncTask$2.call(AsyncTask.java:295)
 at java.util.concurrent.FutureTask.run(FutureTask.java:237)
 at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
 at java.lang.Thread.run(Thread.java:818)

Since, I never touched this code, but I've only added other functionality in other parts of the code, I don't understand what's going on. I've tried to raise the timeout times, but the error actually shows up immediately, so increasing the time seems to be useless. I exclude that this is due to the size of the request, since even if I ask for only a subset of all the JSON it still complains.

It's possible that the problem is in the website that I'm querying? Maybe they have too many request at the moment? Of maybe my phone that I use for developing has been banned for too many requests?

EDIT with additional info: 1) The problems is intermittent. Sometimes the app works fine and all the data are loaded correctly. 2)Sometimes this messages shows up in the LogCat, I'm not sure if is related (the fmradio.jar in particular):

03-12 12:49:36.600 16457-16457/? W/System: ClassLoader referenced unknown path: /data/app/com.example.android.abcfolio-2/lib/arm64
03-12 12:49:36.603 16457-16457/? I/InstantRun: Instant Run Runtime started. Android package is com.example.android.abcfolio, real application class is null.

                                               [ 03-12 12:49:36.607 16457:16457 W/         ]
                                               Unable to open '/system/framework/qcom.fmradio.jar': No such file or directory
03-12 12:49:36.607 16457-16457/? W/art: Failed to open zip archive '/system/framework/qcom.fmradio.jar': I/O Error

                                        [ 03-12 12:49:36.607 16457:16457 W/         ]
                                        Unable to open '/system/framework/oem-services.jar': No such file or directory
03-12 12:49:36.607 16457-16457/? W/art: Failed to open zip archive '/system/framework/oem-services.jar': I/O Error
03-12 12:49:37.149 16457-16470/? I/art: Debugger is no longer active
03-12 12:49:39.030 16457-16457/com.example.android.abcfolio W/System: ClassLoader referenced unknown path: /data/app/com.example.android.abcfolio-2/lib/arm64
03-12 12:49:43.962 16457-16457/com.example.android.abcfolio W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable

3)There other multiple warnings like

W/PathParser: Points are too far apart 4.000000000000003 

These should be due to ConstraintLayout. It is possible that it is using too much memory to perform graphic work on the main thread and this turns into errors in the http request? (it seems unlikely to me, but it could explain why this problem is showing up now, after I've inserted many views with ConstraintLayout)

EDIT 2: 4) In the app I'm fetching the data in two different ways: one with a simple Loader that extends AsyncTaskLoader, and another one with a Firebase Job Service. Is the second one that gives problems, even though they fetch the same API and use both the two methods written above.

EDIT 3: 5) I'm now sure that the problem is not due to changes made recently in the code, since even an older backup version of the app behaves in the same way. 6) Now it's throwing this:

Problem parsing the JSON results
                                             java.io.EOFException
                                                 at com.android.okhttp.okio.RealBufferedSource.require(RealBufferedSource.java:64)
                                                 at com.android.okhttp.okio.RealBufferedSource.readHexadecimalUnsignedLong(RealBufferedSource.java:270)
                                                 at com.android.okhttp.internal.http.HttpConnection$ChunkedSource.readChunkSize(HttpConnection.java:479)
                                                 at com.android.okhttp.internal.http.HttpConnection$ChunkedSource.read(HttpConnection.java:460)
                                                 at com.android.okhttp.okio.RealBufferedSource.read(RealBufferedSource.java:50)
                                                 at com.android.okhttp.okio.RealBufferedSource.exhausted(RealBufferedSource.java:60)
                                                 at com.android.okhttp.okio.InflaterSource.refill(InflaterSource.java:101)
                                                 at com.android.okhttp.okio.InflaterSource.read(InflaterSource.java:62)
                                                 at com.android.okhttp.okio.GzipSource.read(GzipSource.java:80)
                                                 at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:349)
                                                 at java.io.InputStreamReader.read(InputStreamReader.java:233)
                                                 at java.io.BufferedReader.fillBuf(BufferedReader.java:145)
                                                 at java.io.BufferedReader.readLine(BufferedReader.java:397)
                                                 at com.example.android.abcfolio.utils.NetworkCommonUtils.readFromStream(NetworkCommonUtils.java:106)
                                                 at com.example.android.abcfolio.utils.NetworkCommonUtils.makeHttpRequest(NetworkCommonUtils.java:72)
                                                 at com.example.android.abcfolio.utils.NetworkCoinMarketCapUtils.fetchCoinMarketCapData(NetworkCoinMarketCapUtils.java:44)
                                                 at com.example.android.abcfolio.sync.CoinsSyncTask.syncCoins(CoinsSyncTask.java:89)
                                                 at com.example.android.abcfolio.sync.CoinsSyncIntentService.onHandleIntent(CoinsSyncIntentService.java:33)
                                                 at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66)
                                                 at android.os.Handler.dispatchMessage(Handler.java:102)
                                                 at android.os.Looper.loop(Looper.java:148)
                                                 at android.os.HandlerThread.run(HandlerThread.java:61)

EDIT 4: 6) I've logged urlConnection.getResponseCode() + urlConnection.getResponseMessage() and sometimes, instead of the success code 200, it returns: 504Gateway Time-out.

9
  • Have you tried to increase server socket timeout? Usually server socket timeout after 1 or 2 minute. Please test your code with a public rest first to see if timeout is from server or client.. Commented Mar 12, 2017 at 11:04
  • What method should I call to increase server socket timeout? I previously tried with urlConnection.setReadTimeout(10000 /* milliseconds /); urlConnection.setConnectTimeout(15000 / milliseconds */); by doubling these values Commented Mar 12, 2017 at 11:10
  • please test your url with post man to be sure it's worked fine. Commented Mar 12, 2017 at 11:13
  • @Rexcirus You increase server socket timeout from server.. if you have access to server you can try to increase server timeout time. Commented Mar 12, 2017 at 11:16
  • No, I'm querying a public API of some website. Commented Mar 12, 2017 at 11:18

2 Answers 2

1

After many trials, I've concluded indeed that the problem is server side, so there is no real way to solve it. What we can do is to handle gracefully the exception.

Sign up to request clarification or add additional context in comments.

Comments

0

The server is taking longer to service your request than you originally expected when you set the timeouts. They are rather short. They should be in minutes, not seconds.

It doesn't have anything to do with what else your application is doing.

3 Comments

So I simply need to set setReadTimeout and setConnectTimeout to higher values? Let's say 2 minutes or so?
Let's say whatever is going to distinguish between a genuine server failure and a response that took a long time to arrive, taking into account future growth and slowdown. Only you can establish the value for that, and if it was me I would make it configurable.
I've increased the values, but the issue remains. Moreover with a request from AsyncTaskLoader the data are loaded correctly and immediately, and from the same API.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.