1

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;
}   
3
  • @ashoke Large transfers are no more likely to timeout than any other kind. Either some new data arrives within the timeout period of every read or it doesn't. But that single statement was the only thing wrong with your otherwise excellent and correct answer. I've voted to undelete it. Commented Oct 10, 2014 at 23:21
  • I have not solved... i would see again your answer... how to do it? Commented Oct 11, 2014 at 7:52
  • @EJP I was just pointing out we need a way to cancel in middle of large transfers. smartmouse, i undeleted see below Commented Oct 11, 2014 at 18:44

2 Answers 2

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.

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

11 Comments

The size of the response has nothing to do with the probability of a timeout.
@EJP the question mentioned slow connection or user wants to cancel prematurely
Can this code manage if 3g signal suddenly fall down or user disable WiFi during download?
@ashoke: can we speak on live chat somewhere? For example Skype? I need your help :)
@smartmouse your exception handling code will triggered in those cases. Implement above and do a test, post any issues you have.
|
0

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.

2 Comments

I'm using this solution... why someone downvote it? What's wrong?
It isn't necessary, that's what's wrong. Sockets already support timeouts directly. See @ashoke's answer. No need for an extra thread.

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.