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?
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é.
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 :-)
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.
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.
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;
}
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();
}
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);