为异步任务设置超时?

时间:2022-10-14 22:32:40

I have an AsyncTask class that I execute that downloads a big list of data from a website.

我有一个AsyncTask类,我执行它从一个网站下载一个大的数据列表。

In the case that the end user has a very slow or spotty data connection at the time of use, I'd like to make the AsyncTask timeout after a period of time. My first approach to this is like so:

如果最终用户在使用时数据连接非常缓慢或不稳定,我希望在一段时间后使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 );

After starting the AsyncTask, a new handler is started that will cancel the AsyncTask after 30 seconds if it's still running.

在启动AsyncTask之后,将启动一个新的处理程序,如果AsyncTask仍然在运行,这个处理程序将在30秒后取消。

Is this a good approach? Or is there something built into AsyncTask that is better suited for this purpose?

这是一个好的方法吗?还是说,在AsyncTask中存在更适合这个目的的东西?

7 个解决方案

#1


38  

Yes, there is AsyncTask.get()

是的,有AsyncTask.get()

myDownloader.get(30000, TimeUnit.MILLISECONDS);

Note that by calling this in main thread (AKA. UI thread) will block execution, You probably need call it in a separate thread.

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

#2


15  

In the case, your downloader is based upon an for an URL connection, you have a number of parameters that could help you to define a timeout without complex code:

在这种情况下,你的下载程序基于一个URL连接,你有很多参数可以帮助你定义一个没有复杂代码的超时:

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

  urlc.setConnectTimeout(15000);

  urlc.setReadTimeout(15000);

If you just bring this code into your async task, it is ok.

如果您只是将这些代码引入到async任务中,就可以了。

'Read Timeout' is to test a bad network all along the transfer.

“读超时”是在传输过程中测试一个坏的网络。

'Connection Timeout' is only called at the beginning to test if the server is up or not.

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

#3


14  

Use CountDownTimer Class in side the extended class for AsyncTask in the onPreExecute() method:

在onPreExecute()方法中,使用CountDownTimer类来支持AsyncTask的扩展类:

Main advantage, the Async monitoring done internally in the class.

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

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

change CountDownTimer(7000, 7000) -> CountDownTimer(7000, 1000) for example and it will call onTick() 6 times before calling onFinish(). This is good if you want to add some monitoring.

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

Thanks for all the good advice I got in this page :-)

谢谢你在这一页给我的忠告:

#4


2  

I don't think there's anything like that built into AsyncTask. Your approach seems to be a good one. Just be sure to periodically check the value of isCancelled() in your AsyncTask's doInBackground method to end this method once the UI thread cancels it.

我不认为有任何类似的东西构建到AsyncTask中。你的方法似乎不错。只要在UI线程取消该方法时,确保在AsyncTask的doInBackground方法中定期检查iscancel()的值以结束该方法。

If you want to avoid using the handler for some reason, you could check System.currentTimeMillis periodically within your AsyncTask and exit on timeout, although I like your solution better since it can actually interrupt the thread.

如果出于某种原因想避免使用处理程序,可以检查系统。currentTimeMillis周期性地在您的AsyncTask和exit上超时,尽管我更喜欢您的解决方案,因为它实际上可以中断线程。

#5


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

         }

#6


0  

You can put one more condition to make cancellation more robust. e.g.,

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

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

#7


0  

Inspiring from question I have written a method which do some background task via AsyncTask and if processing takes more then LOADING_TIMEOUT then an alert dialogue to retry will appear.

从问题中得到启发,我编写了一个方法,通过AsyncTask执行一些后台任务,如果处理需要更多的加载_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;
}

#1


38  

Yes, there is AsyncTask.get()

是的,有AsyncTask.get()

myDownloader.get(30000, TimeUnit.MILLISECONDS);

Note that by calling this in main thread (AKA. UI thread) will block execution, You probably need call it in a separate thread.

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

#2


15  

In the case, your downloader is based upon an for an URL connection, you have a number of parameters that could help you to define a timeout without complex code:

在这种情况下,你的下载程序基于一个URL连接,你有很多参数可以帮助你定义一个没有复杂代码的超时:

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

  urlc.setConnectTimeout(15000);

  urlc.setReadTimeout(15000);

If you just bring this code into your async task, it is ok.

如果您只是将这些代码引入到async任务中,就可以了。

'Read Timeout' is to test a bad network all along the transfer.

“读超时”是在传输过程中测试一个坏的网络。

'Connection Timeout' is only called at the beginning to test if the server is up or not.

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

#3


14  

Use CountDownTimer Class in side the extended class for AsyncTask in the onPreExecute() method:

在onPreExecute()方法中,使用CountDownTimer类来支持AsyncTask的扩展类:

Main advantage, the Async monitoring done internally in the class.

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

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

change CountDownTimer(7000, 7000) -> CountDownTimer(7000, 1000) for example and it will call onTick() 6 times before calling onFinish(). This is good if you want to add some monitoring.

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

Thanks for all the good advice I got in this page :-)

谢谢你在这一页给我的忠告:

#4


2  

I don't think there's anything like that built into AsyncTask. Your approach seems to be a good one. Just be sure to periodically check the value of isCancelled() in your AsyncTask's doInBackground method to end this method once the UI thread cancels it.

我不认为有任何类似的东西构建到AsyncTask中。你的方法似乎不错。只要在UI线程取消该方法时,确保在AsyncTask的doInBackground方法中定期检查iscancel()的值以结束该方法。

If you want to avoid using the handler for some reason, you could check System.currentTimeMillis periodically within your AsyncTask and exit on timeout, although I like your solution better since it can actually interrupt the thread.

如果出于某种原因想避免使用处理程序,可以检查系统。currentTimeMillis周期性地在您的AsyncTask和exit上超时,尽管我更喜欢您的解决方案,因为它实际上可以中断线程。

#5


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

         }

#6


0  

You can put one more condition to make cancellation more robust. e.g.,

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

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

#7


0  

Inspiring from question I have written a method which do some background task via AsyncTask and if processing takes more then LOADING_TIMEOUT then an alert dialogue to retry will appear.

从问题中得到启发,我编写了一个方法,通过AsyncTask执行一些后台任务,如果处理需要更多的加载_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;
}