简体   繁体   中英

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()

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

You can not show popups/dialogs within doInBackground method. Return null if you get any exceptions and check the return in postExecute method. There you can show the relevant popup/dialogs

You have to call showTimeoutAlert() in the postExecute method because you cannot change the UI in the doInBackground dialog. Return a relsut and then call the method there.

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