Android-为AsyncTask设置超时?


125

我有一个AsyncTask要执行的类,该类从网站下载大量数据。

如果最终用户在使用时数据连接非常慢或参差不齐,我想AsyncTask在一段时间后超时。我的第一个方法是这样的:

MyDownloader downloader = new MyDownloader();
downloader.execute();
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
  @Override
  public void run() {
      if ( downloader.getStatus() == AsyncTask.Status.RUNNING )
          downloader.cancel(true);
  }
}, 30000 );

启动后 AsyncTask,一个新的处理程序被启动,将取消AsyncTask30秒后,如果它仍在运行。

这是一个好方法吗?还是内置一些AsyncTask更适合此目的的东西?


18
在尝试了几种不同的方法之后,我得出结论,您的问题应该是公认的答案。
JohnEye 2012年

感谢您提出的问题,我确实遇到了同样的问题,您的代码段帮助了我+1
Ahmad Dwaik'Warlock'13-10-20

1
您的问题本身就是一个不错的答案+50 :)
karthik kolanji 2015年

Answers:


44

是的,有AsyncTask.get()

myDownloader.get(30000, TimeUnit.MILLISECONDS);

请注意,通过在主线程(AKA.UI线程)中调用此函数将阻止执行,您可能需要在单独的线程中调用它。


9
如果此超时方法在主UI线程上运行,这似乎违反了使用AsyncTask开始的目的...为什么不仅仅使用handler我在问题中描述的方法?似乎更直接了,因为UI线程在等待运行Handler的Runnable时不会冻结...
Jake Wilson

好的,谢谢,我不确定是否有适当的方法来做到这一点。
杰克·威尔逊

3
我不明白为什么您要在另一个线程中调用get()。看起来很奇怪,因为AsyncTask本身是一种线程。我认为Jakobud的解决方案更合适。
emeraldhieu 2012年

我认为.get()与posix线程的联接类似,其目的是等待线程完成。在您的情况下,它用作超时,这是一种间接性质。这就是为什么您需要从处理程序或另一个线程中调用.get()以避免主UI阻塞的原因
Constantine Samoilenko 2016年

2
我知道这是几年后的事,但这仍然不是android内置的,所以我做了一个支持类。我希望它可以帮助某人。gist.github.com/scottTomaszewski/...
斯科特托马谢夫斯基

20

在这种情况下,您的下载器基于URL连接,您有许多参数可以帮助您定义超时而无需复杂的代码:

  HttpURLConnection urlc = (HttpURLConnection) url.openConnection();

  urlc.setConnectTimeout(15000);

  urlc.setReadTimeout(15000);

如果您只是将此代码带入异步任务中,就可以了。

“读取超时”是在整个传输过程中测试不良网络。

仅在开始时调用“连接超时”以测试服务器是否启动。


1
我同意。使用此方法更简单,并且实际上在达到超时时终止连接。使用AsyncTask.get()方法,只会通知您已达到时间限制,但是下载仍在处理中,并且实际上可能会在以后完成-导致代码更加复杂。谢谢。
昏昏欲睡的

请注意,在非常慢的Internet连接上使用大量线程时,这还不够。更多信息:leakfromjavaheap.blogspot.nl/2013/12/...thushw.blogspot.nl/2010/10/...
Kapitein Witbaard

20

在onPreExecute()方法中,在AsyncTask扩展类的旁边使用CountDownTimer类:

主要优点是,异步监视在类内部完成。

public class YouExtendedClass extends AsyncTask<String,Integer,String> {
...
public YouExtendedClass asyncObject;   // as CountDownTimer has similar method -> to prevent shadowing
...
@Override
protected void onPreExecute() {
    asyncObject = this;
    new CountDownTimer(7000, 7000) {
        public void onTick(long millisUntilFinished) {
            // You can monitor the progress here as well by changing the onTick() time
        }
        public void onFinish() {
            // stop async task if not in progress
            if (asyncObject.getStatus() == AsyncTask.Status.RUNNING) {
                asyncObject.cancel(false);
                // Add any specific task you wish to do as your extended class variable works here as well.
            }
        }
    }.start();
...

更改CountDownTimer(7000,7000)-> CountDownTimer(7000,1000)例如,它将在调用onFinish()之前调用onTick()6次。如果要添加一些监视,这很好。

感谢您在此页面中提供的所有建议:-)


2

我不认为AsyncTask内置了类似功能。您的方法似乎是一种不错的方法。只要确保定期检查AsyncTask的doInBackground方法中isCancelled()的值,以在UI线程取消它后结束该方法。

如果您出于某种原因想要避免使用处理程序,则可以在AsyncTask中定期检查System.currentTimeMillis并在超时时退出,尽管我更喜欢您的解决方案,因为它实际上可以中断线程。


0
         Context mContext;

         @Override
         protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
                                    mContext = this;

            //async task
            final RunTask tsk = new RunTask (); 
            tsk.execute();

            //setting timeout thread for async task
            Thread thread1 = new Thread(){
            public void run(){
                try {
                    tsk.get(30000, TimeUnit.MILLISECONDS);  //set time in milisecond(in this timeout is 30 seconds

                } catch (Exception e) {
                    tsk.cancel(true);                           
                    ((Activity) mContext).runOnUiThread(new Runnable()
                    {
                         @SuppressLint("ShowToast")
                        public void run()
                         {
                            Toast.makeText(mContext, "Time Out.", Toast.LENGTH_LONG).show();
                            finish(); //will close the current activity comment if you don't want to close current activity.                                
                         }
                    });
                }
            }
        };
        thread1.start();

         }

2
考虑加入一些解释,以及
赛义夫·阿西夫

0

您可以再添加一个条件以使取消更可靠。例如,

 if (downloader.getStatus() == AsyncTask.Status.RUNNING || downloader.getStatus() == AsyncTask.Status.PENDING)
     downloader.cancel(true);

0

从问题中得到启发,我编写了一种方法,该方法通过AsyncTask执行一些后台任务,如果处理花费的时间超过LOADING_TIMEOUT,则将出现警告对话框以重试。

public void loadData()
    {
        final Load loadUserList=new Load();
        loadUserList.execute();
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (loadUserList.getStatus() == AsyncTask.Status.RUNNING) {
                    loadUserList.cancel(true);
                    pDialog.cancel();
                    new AlertDialog.Builder(UserList.this)
                            .setTitle("Error..!")
                            .setMessage("Sorry you dont have proper net connectivity..!\nCheck your internet settings or retry.")
                            .setCancelable(false)
                            .setPositiveButton("Retry", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    loadData();
                                }
                            })
                            .setNegativeButton("Exit", new DialogInterface.OnClickListener() {
                                @Override


                      public void onClick(DialogInterface dialogInterface, int i) {
                                System.exit(0);
                            }
                        })
                        .show();
            }
        }
    }, LOADING_TIMEOUT);
    return;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.