公认的答案有一些显著的缺点。除非您确实知道自己在做什么,否则不建议将AsyncTask用于网络。一些缺点包括:
创建为非静态内部类的AsyncTask对封闭的Activity对象、其上下文和该活动创建的整个View层次结构具有隐式引用。此引用防止在AsyncTask的后台工作完成之前对“活动”进行垃圾收集。如果用户的连接速度慢,和/或下载量大,这些短期内存泄漏可能会成为一个问题,例如,如果方向多次更改(并且您没有取消正在执行的任务),或者用户导航离开“活动”。AsyncTask具有不同的执行特性,这取决于它执行的平台:在API级别4之前,AsyncTask在单个后台线程上串行执行;从API级别4到API级别10,AsyncTask在最多128个线程的池中执行;从API级别11开始,AsyncTask在单个后台线程上串行执行(除非您使用重载的executeOnExecutor方法并提供替代的执行器)。在ICS上串行运行时工作良好的代码在Gingerbread上并行执行时可能会中断,比如说,如果您无意中有执行依赖关系的顺序。
如果您希望避免短期内存泄漏,在所有平台上都具有定义良好的执行特性,并拥有构建真正强大的网络处理的基础,您可能需要考虑:
使用一个库可以很好地完成这项工作-在这个问题中可以很好的比较网络库,或者而是使用Service或IntentService,或者使用PendingIntent,通过Activity的onActivityResult方法返回结果。
IntentService方法
缺点:
比AsyncTask更多的代码和复杂性,尽管没有您想象的那么多将请求排队并在单个后台线程上运行它们。您可以通过将IntentService替换为等效的服务实现(可能像这样)来轻松控制这一点。嗯,我现在真的想不出其他人了
优点:
避免短期内存泄漏问题如果您的活动在网络操作进行时重新启动,它仍然可以通过其onActivityResult方法接收下载结果一个比AsyncTask更好的平台来构建和重用健壮的网络代码。示例:如果您需要执行重要的上载,可以从“活动”中的AsyncTask执行,但如果用户上下文切换到应用程序之外以接听电话,则系统可能会在上载完成之前关闭应用程序。不太可能终止具有活动服务的应用程序。如果您使用自己的IntentService并发版本(如我上面链接的版本),您可以通过Executor控制并发级别。
实施总结
您可以很容易地实现IntentService在单个后台线程上执行下载。
步骤1:创建IntentService以执行下载。您可以通过Intent extra告诉它要下载什么,并将PendingIntent传递给它,用于将结果返回给“活动”:
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 reuse, 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);
}
}
}
步骤2:在清单中注册服务:
<service
android:name=".DownloadIntentService"
android:exported="false"/>
步骤3:从“活动”调用服务,传递PendingResult对象,服务将使用该对象返回结果:
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);
步骤4:在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);
}
这里有一个GitHub项目,包含一个完整的Android Studio/Gradle项目。