Il existe plusieurs alternatives pour la accepté de répondre, chacun avec différents arbitrages. Permettez-moi de commencer par dire que l'on a accepté la réponse est bonne, et moi-voter, mais il n'est pas la seule et elle a quelques bas-côtés:
- AsyncTask est créée comme non-statique à l'intérieur des classes ont une référence implicite à l'encadrement de l'Activité de l'objet, de son contexte, et la Vue d'ensemble de la hiérarchie créée par cette activité. Cette référence empêche l'Activité de déchets collectés jusqu'à l'AsyncTask du travail de fond complète. Si la connexion de l'utilisateur est lent, et/ou le téléchargement est grand, ces court-terme des fuites de mémoire peut devenir un problème, si par exemple, les changements d'orientation plusieurs fois (et vous n'avez pas annuler l'exécution de tâches), ou que l'utilisateur accède à l'écart de l'Activité.
- AsyncTask est différent de l'exécution des caractéristiques dépendant de la plate-forme s'exécute sur: avant API de niveau 4 AsyncTasks exécuter en série sur un seul thread d'arrière-plan; à partir de l'API de niveau 4 par le biais de l'API de niveau 10, AsyncTasks exécuter sur un bassin allant jusqu'à 128 threads; à partir de l'API de niveau 11, AsyncTask exécute en série sur un seul thread d'arrière-plan (sauf si vous utilisez la surcharge
executeOnExecutor
méthode et offre une alternative exécuteur testamentaire). Code qui fonctionne très bien lorsqu'il est exécuté en série sur ICS peuvent se briser lorsqu'elles sont exécutées simultanément sur pain d'épice, disons, si vous avez par inadvertance ordre d'exécution des dépendances.
Si vous voulez éviter de court-terme des fuites de mémoire, ont bien défini exécution caractéristiques à travers toutes les plateformes, et avoir une base pour construire vraiment solide réseau de manutention, vous pourriez envisager:
- À l'aide d'une bibliothèque qui fait un excellent travail pour vous - il y a une belle comparaison de la mise en réseau libs dans cette question, ou
- À l'aide d'un
Service
ou IntentService
au lieu de cela, peut-être avec un PendingIntent
de renvoyer le résultat via l'Activité, en onActivityResult
méthode.
IntentService approche
Les bas-côtés:
- Plus de code et de complexité qu'
AsyncTask
, bien que pas autant que vous pourriez le penser
- Aura la file d'attente de demandes et de les exécuter sur un seul thread d'arrière-plan. Vous pouvez facilement contrôler ce problème en remplaçant
IntentService
avec un équivalent Service
mise en œuvre, peut-être comme cette une.
- Euh, je ne peux pas penser à d'autres le droit maintenant en fait
Jusqu'à-côtés:
- Évite le court terme, problème de fuite de mémoire
- Si votre activité redémarre alors que les opérations de réseau sont en vol, il peut toujours recevoir le résultat de la télécharger via son
onActivityResult
méthode
- Meilleure plate-forme que les AsyncTask de construire et de ré-utilisation robuste code réseau. Exemple: si vous avez besoin de faire une importante télécharger, vous pouvez le faire à partir d'
AsyncTask
en Activity
, mais si le contexte de l'utilisateur-permet de sortir de l'application pour prendre un appel, le système peut tuer l'application avant que le téléchargement se termine. Il est moins susceptible de tuer une application avec un actif Service
.
- Si vous utilisez votre propre version simultanée d'
IntentService
(comme celle que j'ai lié ci-dessus), vous pouvez contrôler le niveau de la concurrence via l' Executor
.
La mise en œuvre résumé
Vous pouvez mettre en œuvre un IntentService
pour effectuer des téléchargements sur un seul thread d'arrière-plan assez facilement.
Étape 1: Créer un IntentService
pour effectuer le téléchargement. Vous pouvez dire ce qui est à télécharger via Intent
supplémentaires, et de passer à un PendingIntent
d'utilisation de retourner le résultat de l' Activity
:
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
public class DownloadIntentService extends IntentService {
private static final String TAG = DownloadIntentService.class.getSimpleName();
public static final String PENDING_RESULT_EXTRA = "pending_result";
public static final String URL_EXTRA = "url";
public static final String RSS_RESULT_EXTRA = "url";
public static final int RESULT_CODE = 0;
public static final int INVALID_URL_CODE = 1;
public static final int ERROR_CODE = 2;
private IllustrativeRSSParser parser;
public DownloadIntentService() {
super(TAG);
// make one and re-use, in the case where more than one intent is queued
parser = new IllustrativeRSSParser();
}
@Override
protected void onHandleIntent(Intent intent) {
PendingIntent reply = intent.getParcelableExtra(PENDING_RESULT_EXTRA);
InputStream in = null;
try {
try {
URL url = new URL(intent.getStringExtra(URL_EXTRA));
IllustrativeRSS rss = parser.parse(in = url.openStream());
Intent result = new Intent();
result.putExtra(RSS_RESULT_EXTRA, rss);
reply.send(this, RESULT_CODE, result);
} catch (MalformedURLException exc) {
reply.send(INVALID_URL_CODE);
} catch (Exception exc) {
// could do better by treating the different sax/xml exceptions individually
reply.send(ERROR_CODE);
}
} catch (PendingIntent.CanceledException exc) {
Log.i(TAG, "reply cancelled", exc);
}
}
}
Étape 2: Inscrivez-vous au service dans le manifeste:
<service
android:name=".DownloadIntentService"
android:exported="false"/>
Étape 3: Appeler le service à partir de l'Activité, le passage d'un PendingResult objet dont le Service va utiliser pour renvoyer le résultat:
PendingIntent pendingResult = createPendingResult(
RSS_DOWNLOAD_REQUEST_CODE, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), DownloadIntentService.class);
intent.putExtra(DownloadIntentService.URL_EXTRA, URL);
intent.putExtra(DownloadIntentService.PENDING_RESULT_EXTRA, pendingResult);
startService(intent);
Étape 4: Gérer le résultat dans onActivityResult:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RSS_DOWNLOAD_REQUEST_CODE) {
switch (resultCode) {
case DownloadIntentService.INVALID_URL_CODE:
handleInvalidURL();
break;
case DownloadIntentService.ERROR_CODE:
handleError(data);
break;
case DownloadIntentService.RESULT_CODE:
handleRSS(data);
break;
}
handleRSS(data);
}
super.onActivityResult(requestCode, resultCode, data);
}
Un projet github contenant un travail complet Android-Studio/gradle projet est disponible ici.