简体   繁体   中英

kills an Android AsyncTask with a timeout

So my problem is that i have a AsyncTask that scraps html from a page on a server so i used Jsoup as a library . so the problem is that i want to set a timeout to cancel the Task if i don't receive any data from the page and display that there is a "communication error " on a toast

is there anyway to kill or stop the asynctask within it self and return a result on onPostExecute

{
private class getPageTitle extends AsyncTask<Void, Void, String> {
        String title;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            connectServerProgressDialog = new ProgressDialog(LoginScreen.this);
            connectServerProgressDialog.setTitle("CheckingServer");
            connectServerProgressDialog.setMessage("Loading...");
            connectServerProgressDialog.setIndeterminate(true);

            connectServerProgressDialog.show();
        }

        @Override
        protected String doInBackground(Void... params) {


            try {

                // Connect to the web site
                                Document document = Jsoup.connect(CONNECT_URL).get();

                            title = document.title();

                           } catch (IOException e) {

                e.printStackTrace();
            }

            return null ;
        }

        @Override
        protected void onPostExecute(String result) {

            if(result!=null){

            switch (title) {
                case "0":
                    Toast.makeText(LoginScreen.this,"offline",Toast.LENGTH_SHORT).show();
                    connectServerProgressDialog.dismiss();
                    break;
                case "1":
                    connectServerProgressDialog.dismiss();
                     Toast.makeText(LoginScreen.this,"Connected",Toast.LENGTH_SHORT).show();
                    break;

            }}else{
                Toast.makeText(LoginScreen.this,"Communication error",Toast.LENGTH_SHORT).show();
            }

            }
        }}

I have a convention that I use for AsyncTask subclasses.

  • Define an inner interface for the client to use. This decouples the client class so that the AsyncTask can be re-used. The interface is named in the form blahblahListener .
  • The interface has two methods of the form blahblahCompleted() and blahblahException() .
  • Accept a callback object (listener) that is an implementation of that interface. This is either passed in the AsyncTask constructor or set with a setListener() method.
  • Hold that listener reference in a WeakReference field so that if the listener goes away before the task completes, the listener can still be garbage-collected.
  • Define a field to hold an Exception . If an exception occurs in the background method, this field remembers the exception in order to report it to the client.
  • In the onPostExecute() method, check if the Exception field is null. If it is, call blahblahCompleted() with the result. If it isn't, call blahblahException() with the exception. Also check if the WeakReference is still valid.

For killing the task, you can have a timeout set on your connection. Then when your connection times out, you will get an exception, which is remembered and reported.

So using that convention, your code would look like this:

public class WebPageTitleRemoteTask extends AsyncTask<URL, Void, String> {

    private WeakReference<WebPageTitleRetrievalListener> mListener;

    private Exception mException;

    public WebPageTitleRemoteTask(WebPageTitleRetrievalListener listener) {
        super();
        mListener = new WeakReference<WebPageTitleRetrievalListener>(listener);
    }

    @Override
    protected String doInBackground(URL... params) {

        String title = null;

        try {
            // Connect to the web site
            Document document = Jsoup.connect(params[0]).get();
            title = document.title();

        } catch (IOException e) {
            mException = e;
        }

        return title;
    }

    @Override
    protected void onPostExecute(String result) {

        WebPageTitleRetrievalListener listener = mListener.get();
        if (listener != null) {
            if (mException == null) {
                listener.webPageTitleRetrieved(result);
            } else {
                listener.webPageTitleRetrievalException(mException);
            }
        }
    }

    public static interface WebPageTitleRetrievalListener {

        public void webPageTitleRetrieved(String title);

        public void webPageTitleRetrievalException(Exception e);
    }

}

And your client code would look something like this, with your Activity implementing that inner interface:

    .
    .
    .
    connectServerProgressDialog = new ProgressDialog(LoginScreen.this);
    connectServerProgressDialog.setTitle("CheckingServer");
    connectServerProgressDialog.setMessage("Loading...");
    connectServerProgressDialog.setIndeterminate(true);

    connectServerProgressDialog.show();

    new WebPageTitleRemoteTask(this).execute(url);
    .
    .
    .

@Override
public void webPageTitleRetrieved(String title) {

    if (isFinishing()) return;
    connectServerProgressDialog.dismiss();
    Toast.makeText(this, "title = " + title, Toast.LENGTH_SHORT).show();
}

@Override
public void webPageTitleRetrievalException(Exception e) {

    if (isFinishing()) return;
    connectServerProgressDialog.dismiss();
    Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}

NOTE: Because the listener is held in a WeakReference , you can't use an anonymous inner class for the listener, because the reference will go away almost immediately and be eligible for garbage collection.

I use this convention consistently, and the extra boilerplate code in the AsyncTask subclass makes it a lot cleaner to use in the client class.

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