Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Handling SocketTimeoutException inside AsyncTask with a simple Alert Dialog

I use AsyncTask in my Android app to fetch some data from a server. To make the connection, I use the HttpURLConnection class with a timeout of 10 seconds. Now, I would like to show a simple AlertDialog when (if) that time expires, with an OK button that takes the user back to Main Activity. Right now, this is what the relevant part of my app (DoorActivity) looks like:

    protected String doInBackground(String... params) {

        try {

            URL url = new URL(params[0]);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setConnectTimeout(10000);
            urlConnection.setRequestMethod("GET");
            if (urlConnection.getResponseCode() != 200) {
                throw new IOException(urlConnection.getResponseMessage());
            }

            BufferedReader read = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            jsonString = read.readLine().toString();

        } catch (MalformedURLException malformedUrlException) {
            System.out.println(malformedUrlException.getMessage());
            malformedUrlException.printStackTrace();

        } catch (SocketTimeoutException connTimeout) {
            showTimeoutAlert();

showTimeoutAlert() method is located in the root class of DoorActivity, and looks like this:

protected void showTimeoutAlert(){
    TextView timeoutWarning = new TextView(this);
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    AlertDialog alertDialog;
    timeoutWarning.setText(R.string.conn_timeout_warning);
    builder.setView(timeoutWarning);
    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            Intent intent = new Intent(DoorActivity.this, MainActivity.class);
            startActivity(intent);
        }
    });
    alertDialog = builder.create();
    alertDialog.show();
}

Now, when I run this app, with the server deliberately offline, I get the following exception:

java.lang.RuntimeException: An error occured while executing doInBackground()

Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

like image 860
Marko J. Avatar asked Oct 19 '22 18:10

Marko J.


1 Answers

showTimeoutAlert(); should not be called in doInBackground(). Any code related to UI should go in onPostExecute() instead.

For example:

private boolean socketTimedOut = false;

@Override
protected String doInBackground(String... params) {
    try {
        ...
    } catch (SocketTimeoutException connTimeout) {
        this.socketTimedOut = true;
    }
}


@Override
protected void onPostExecute(String result) {
    if(this.socketTimedOut){
        showTimeoutAlert();
    }
}

Alternative solution (not recommended):

@Override
protected String doInBackground(String... params) {
    try {
        ...
    } catch (SocketTimeoutException connTimeout) {
        runOnUiThread(new Runnable() {
            public void run() {
                showTimeoutAlert();
            }
        });
    }
}       
like image 68
meda Avatar answered Oct 21 '22 16:10

meda