简体   繁体   中英

How to add HttpClient request and connection timeout in Android

I'm developing my first app and i create the following method that connects to a remote url, gets a JSON file and writes it to local SQLite database. Sometimes happens that the internet connection is slow or bad and i would set a timer. For example if after 3 seconds it doesn't get the JSON file i would throw an AlertDialog to make user to choose if retry or cancel. So how to add timeout to my function?

public int storeData(Database db, int num) throws JSONException {

    HttpClient client = new DefaultHttpClient();
    HttpGet request = new HttpGet("http://www.example.com/file.json");
    request.addHeader("Cache-Control", "no-cache");
    long id = -1;

    try {
        HttpResponse response = client.execute(request);
        HttpEntity entity = response.getEntity();
        InputStreamReader in = new InputStreamReader(entity.getContent());
        BufferedReader reader = new BufferedReader(in);
        StringBuilder stringBuilder = new StringBuilder();
        String line = "";

        while ((line=reader.readLine()) != null) {
            stringBuilder.append(line);
        }

        JSONArray jsonArray = new JSONArray(stringBuilder.toString());
        SQLiteDatabase dbWrite = db.getWritableDatabase();
        ContentValues values = new ContentValues();
        if (jsonArray.length() == num && num != 0)
            return num;
        SQLiteDatabase dbread = db.getReadableDatabase();

        for (int i = 0; i < jsonArray.length(); i++) {
            JSONObject jObj = (JSONObject) jsonArray.getJSONObject(i);

            values.put("id", jObj.optString("id").toString());
            values.put("name", jObj.optString("firstname").toString());
            values.put("surname",jObj.optString("lastname").toString());

            id = dbWrite.insert("users", null, values);
        }
        num = jsonArray.length();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    if (id > 0)
        return num;
    else
        return -1;
}   

Few things to consider :

  • Timeouts on socket and HTTP connections

    First, modify your HTTP connection to have connection and socket timeouts

      BasicHttpParams basicParams = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout( basicParams, timeout * 1000 ); HttpConnectionParams.setSoTimeout( basicParams, timeout * 1000 ); DefaultHttpClient client = new DefaultHttpClient( basicParams ); 
  • Exiting your pending request gracefully on timeout

    • You may run out of time on slow connection if response data is big, in which case, we need to gracefully close the HTTPClient resources.

    • I assume you already have this storeData called in a separate thread, I suggest you use AsyncTask , as we can call its cancel method on timeout. Your storeData code will be in asyncTask's doInBackground , and in the 'while` loop where you read entity response data, you can check for isCancelled of AsyncTask and gracefully close

       if (isCancelled()) { EntityUtils.consume(entity); client.getConnectionManager().shutdown(); return -1; } 
    • In the postExecute function of asyncTask, you can set the isDone to indicate successful request without any timeout and any other UI handling.

       protected void onPostExecute(...) { isDone = true; } 
  • Scheduling and handling the timeout on main UI Thread

    The above two will take care of connection timeouts, data timeouts, and slow connection timeouts. Now, we need to handle setting the timeout and managing it from UI. For this, we can just use a simple delayed handler runnable as @Neutrino suggested.

      boolean isDone = false; StoreDataTask storeDataTask = new StoreDataTask(); storeDataTask.execute(...) new Handler().postDelayed(new Runnable() { public void run() { storeDataTask.cancel(false); } }, timeout * 1000); if (isDone) // we have a successful request without timeout 

    wrap the above snippet in a function and call it again if user wants to retry. Note, you can call storeDataTask.cancel(false); anytime from your onCreate or UI thread if user does not want to wait for the timeout and just wants to cancel it.

Use handler like this -

final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        //Check if JSON file is there
        //This code will be executed after 3 seconds
    }
}, 3000); //Change time here. The time is in milliseconds. 1 sec = 1000 ms.
         //The code above will be executed after given time.

Put this code at end.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM