简体   繁体   中英

My code will not cancel AsyncTask when it should on android

I want to cancel an AsyncTask after a timeout if the task is still running and I want to cancel it immediately. Here is my code:

HttpURLConnection connection = null;
//GetRequestTask extends AsyncTask
final GetRequestsTask requestTask = new GetRequestsTask();
requestTask.execute(createUrl());
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        Log.d("myapp", "entered handler");
        if (requestTask.getStatus() == AsyncTask.Status.RUNNING) {
            Log.d("myapp", "entered cancelling");
            requestTask.cancel(true);
            connection.disconnect();
        }
    }
}, TIME_OUT);

As you can see, I am calling a HTTP request in my AsyncTask 's doInBackground method. and when I want to cancel the AsyncTask I also disconnect the connection.

The problem is that when I call cancel(true) and my app logs entered cancelling , the AsynkTask won't cancel immediately and will cancel with a minimum 10 to 20 seconds delay.

what should I do to cancel the task as soon as I call cancel?

UPDATE: This is my `AsyncTask code:

private class GetRequestsTask extends AsyncTask<URL, Void, JSONObject> {

        @Override
        protected void onPreExecute() {
            Log.d("myapp", "entered onPreExecute");
            mLoadingDialog.show();
        }

        @Override
        protected JSONObject doInBackground(URL... urls) {
            Log.d("myapp", "entered doInBackground");
            try {
                connection = (HttpURLConnection) urls[0].openConnection();
                connection.setRequestProperty("Accept", "application/json");
                int response = connection.getResponseCode();

                if (response == HttpURLConnection.HTTP_OK) {
                    StringBuilder builder = new StringBuilder();

                    BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                    try {
                        String line;

                        while ((line = reader.readLine()) != null) {
                            builder.append(line);
                        }
                    }
                    catch (IOException e) {
                        e.printStackTrace();
                    }
                    finally {
                        reader.close();
                    }

                    return new JSONObject(builder.toString());
                }
                else {

                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            finally {
                connection.disconnect();
            }
            return null;
        }

        @Override
        protected void onPostExecute(JSONObject jsonObject) {
            Log.d("myapp", "entered onPostExecute");
            mLoadingDialog.dismiss();
            if (jsonObject == null) {
                showNoInternetDialog();
            }
            else {
                convertJSONtoArrayList(jsonObject);
                mRequestArrayAdapter.notifyDataSetChanged();
                mListView.smoothScrollToPosition(0);
            }
        }

        @Override
        protected void onCancelled() {
            Log.d("myapp", "entered onCancelled");
            mLoadingDialog.dismiss();
            showNoInternetDialog();
        }

The problem is that my timeout is 20 seconds, but onCancelled is called after 35, 40 seconds.

From this question :

If you're doing computations:

  • You have to check isCancelled() periodically.

If you're doing a HTTP request:

  • Save the instance of your HttpGet or HttpPost somewhere (eg. a public field).
  • After calling cancel, call request.abort(). This will cause IOException be thrown inside your doInBackground.

Additionally if you use some library to provide convenient requests, then I think it should have some cancel() method. For example, for retrofit there is such method.

So in this case like for 'If you're doing a HTTP request' section. you need to:

  • Save the instance of your request (for retrofit it's Call)
  • After calling cancel, call 'cancel' method for saved instance of request.

And one more alternative is rxJava. With help of this library you can create Observable for your request and save reference to its subscription. Then you just need to call savedSubscription.unsubscribe() and that's it.

Also, please, do not use Async tasks as inner classes.

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