Android: ¿configurar un tiempo de espera para una AsyncTask?

Tengo una clase AsyncTask que ejecuto que descarga una gran lista de datos de un sitio web.

En el caso de que el usuario final tenga una conexión de datos muy lenta o irregular en el momento del uso, me gustaría hacer que el tiempo de espera de AsyncTask después de un período de tiempo. Mi primer acercamiento a esto es así:

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

Después de iniciar AsyncTask , se AsyncTask un nuevo controlador que cancelará la AsyncTask después de 30 segundos si aún se está ejecutando.

¿Es este un buen enfoque? ¿O hay algo incorporado en AsyncTask que sea más adecuado para este propósito?

Sí, hay AsyncTask.get ()

 myDownloader.get(30000, TimeUnit.MILLISECONDS); 

Tenga en cuenta que al invocar esto en el hilo principal (AKA. UI thread) se bloqueará la ejecución. Probablemente necesite llamarlo en un hilo separado.

En este caso, su descargador se basa en una conexión de URL, usted tiene una serie de parámetros que podrían ayudarlo a definir un tiempo de espera sin código complejo:

  HttpURLConnection urlc = (HttpURLConnection) url.openConnection(); urlc.setConnectTimeout(15000); urlc.setReadTimeout(15000); 

Si solo traes este código a tu tarea asíncrona, está bien.

‘Leer tiempo de espera’ es probar una red defectuosa a lo largo de la transferencia.

‘Connection Timeout’ solo se llama al principio para probar si el servidor está activo o no.

Use CountDownTimer Class en el lado de la clase extendida para AsyncTask en el método onPreExecute ():

La principal ventaja es la monitorización Async realizada internamente en la clase.

 public class YouExtendedClass extends AsyncTask { ... 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(); ... 

cambie CountDownTimer (7000, 7000) -> CountDownTimer (7000, 1000) por ejemplo y llamará a Tick () 6 veces antes de llamar a Finish (). Esto es bueno si quieres agregar algo de monitoreo.

Gracias por todos los buenos consejos que recibí en esta página 🙂

No creo que haya nada de eso integrado en AsyncTask. Tu enfoque parece ser bueno. Solo asegúrese de comprobar periódicamente el valor de isCancelled () en el método doInBackground de su AsyncTask para finalizar este método una vez que el subproceso de la interfaz de usuario lo cancela.

Si desea evitar el uso del controlador por alguna razón, puede verificar System.currentTimeMillis periódicamente en su AsyncTask y salir del tiempo de espera, aunque me gusta más su solución ya que realmente puede interrumpir el hilo.

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

Puede poner una condición más para que la cancelación sea más sólida. p.ej,

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

Inspirando en la pregunta He escrito un método que hace algunas tareas en segundo plano a través de AsyncTask y si el proceso tarda más que LOADING_TIMEOUT, aparecerá un diálogo de alerta para volver a intentar.

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