2017-03-12 45 views
0

我正在通過GET請求從Web獲取JSON數據。代碼如下,儘管問題似乎是「概念上的」。Android中的SocketTimeoutException超時

/** 
* 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(); 
} 

事實上,下面的代碼工作了幾個月,卻突然開始嘔吐:

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) 

,因爲我從來沒有碰過這樣的代碼,但我只在代碼的其他部分增加了其他功能,我不明白髮生了什麼事。我試圖提高超時時間,但錯誤實際上立即顯示出來,所以增加時間似乎是無用的。 我排除這是由於請求的大小,因爲即使我只要求所有JSON的一個子集,它仍然抱怨。

問題可能出在我查詢的網站上?也許他們目前有太多的要求?我用於開發的手機可能有太多請求被禁止了嗎?

EDIT與附加信息: 1)存在的問題是間歇性的。有時應用程序工作正常,所有的數據加載正確。 2)有時,這種消息顯示了在logcat中,我不知道,如果是相關的(尤其是fmradio.jar):

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)有其他多個警告信息,如

W/PathParser: Points are too far apart 4.000000000000003 

這些應該是由於ConstraintLayout。它可能會使用太多的內存在主線程上執行圖形工作,並且這會變成http請求中的錯誤? (這似乎不太可能對我來說,但它可以解釋爲什麼現在出現這個問題,因爲我已經用ConstraintLayout插入了很多視圖)

編輯2: 4)在應用程序中,我將數據提取到兩個不同的方式:使用一個簡單的Loader擴展AsyncTaskLoader,另一個使用Firebase Job Service。是第二個問題,即使他們獲取相同的API並使用上面寫的兩個方法。

編輯3: 5)我現在確定問題不是由於最近在代碼中所做的更改導致的,因爲即使應用程序的較舊備份版本的行爲方式相同。 6)現在它拋出這樣的:

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) 

編輯4: 6)我已經登錄urlConnection.getResponseCode()+ urlConnection.getResponseMessage(),有時,而不是成功代碼200,它返回:504Gateway時間到。

+0

您是否嘗試過增加服務器套接字超時?通常服務器套接字在1或2分鐘後超時。請先使用公共休息來測試您的代碼,以查看服務器或客戶端是否超時。 –

+0

我應該調用什麼方法來增加服務器套接字超時?我以前嘗試使用urlConnection.setReadTimeout(10000/*毫秒* /); urlConnection.setConnectTimeout(15000/*毫秒* /);通過加倍這些值 – Rexcirus

+0

請測試您的網址與郵政人,以確保它的工作正常。 – Ibrahim

回答

0

經過多次試驗,我已經斷定問題是服務器端,所以沒有真正的解決方法。 我們可以做的是優雅地處理異常。

0

當您設置超時時,服務器花費的時間比您最初預計的時間要長。它們相當短。他們應該在幾分鐘內,而不是幾秒鐘。

它與您的應用程序正在做什麼沒有任何關係。

+0

所以我只需要將setReadTimeout和setConnectTimeout設置爲更高的值?假設2分鐘左右? – Rexcirus

+0

讓我們說一下,無論怎樣區分真正的服務器故障和需要很長時間才能到達的響應,同時考慮到未來的增長和放緩。只有你可以確定它的價值,如果是我,我會讓它成爲可配置的。 – EJP

+0

我增加了值,但問題依然存在。此外,通過AsyncTaskLoader的請求,數據可以立即正確加載,並且來自相同的API。 – Rexcirus

相關問題