web-dev-qa-db-fra.com

Android - Définition d'un délai d'attente pour une tâche asynchrone?

J'ai une classe AsyncTask que j'exécute qui télécharge une grande liste de données d'un site Web.

Dans le cas où l'utilisateur final dispose d'une connexion de données très lente ou inégale au moment de son utilisation, j'aimerais que le délai d'expiration de AsyncTask soit écoulé après une certaine période. Ma première approche est la suivante:

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

Après le démarrage de AsyncTask, un nouveau gestionnaire est démarré. Il annulera AsyncTask après 30 secondes s'il est toujours en cours d'exécution.

Est-ce une bonne approche? Ou y a-t-il quelque chose de construit dans AsyncTask qui conviendrait mieux à cette fin?

122
Jake Wilson

Oui, il y a AsyncTask.get ()

myDownloader.get(30000, TimeUnit.MILLISECONDS);

Notez qu'en appelant ceci dans le thread principal (AKA. UI thread) bloquera l'exécution, vous devrez probablement l'appeler dans un thread séparé.

41
yorkw

Utilisez CountDownTimer Class dans la classe étendue pour AsyncTask dans la méthode onPreExecute ():

Principal avantage, la surveillance Async réalisée en interne dans la classe.

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

changez CountDownTimer (7000, 7000) -> CountDownTimer (7000, 1000) par exemple et il appellera onTick () 6 fois avant d'appeler onFinish (). C'est bien si vous voulez ajouter un peu de surveillance.

Merci pour tous les bons conseils que j'ai reçus sur cette page :-)

17
Gilco

Dans le cas, votre téléchargeur est basé sur une connexion URL, vous avez un certain nombre de paramètres qui pourraient vous aider à définir un délai d’expiration sans code complexe:

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

  urlc.setConnectTimeout(15000);

  urlc.setReadTimeout(15000);

Si vous apportez simplement ce code dans votre tâche async, c'est ok.

Le "délai de lecture" consiste à tester un mauvais réseau tout au long du transfert.

'Connection Timeout' n'est appelé au début que pour tester si le serveur est actif ou non.

17
Clement Soullard

Je ne pense pas qu'il y ait quelque chose de semblable dans AsyncTask. Votre approche semble être bonne. Assurez-vous simplement de vérifier périodiquement la valeur de isCancelled () dans la méthode doInBackground de votre AsyncTask pour mettre fin à cette méthode une fois que le thread d'interface utilisateur l'a annulée.

Si vous souhaitez éviter d'utiliser le gestionnaire pour une raison quelconque, vous pouvez vérifier périodiquement System.currentTimeMillis dans votre AsyncTask et quitter le délai d'attente, bien que j'aime mieux votre solution car elle peut réellement interrompre le thread.

2
aleph_null

Inspirant d’une question, j’ai écrit une méthode qui effectue une tâche d’arrière-plan via AsyncTask et si le traitement prend plus de temps que LOADING_TIMEOUT, un dialogue d’alerte à réessayer apparaîtra.

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

         }
0
Mrityunjaya

Vous pouvez mettre une condition supplémentaire pour rendre l'annulation plus robuste. par exemple.,

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