在 Android 中发出异步 HTTP 请求是不是有公认的最佳实践?

Posted

技术标签:

【中文标题】在 Android 中发出异步 HTTP 请求是不是有公认的最佳实践?【英文标题】:Is there an accepted best-practice on making asynchronous HTTP requests in Android?在 Android 中发出异步 HTTP 请求是否有公认的最佳实践? 【发布时间】:2010-10-24 02:50:36 【问题描述】:

我见过很多例子,它们似乎都以不同的方式解决了这个问题。基本上我只想要最简单的方法来发出不会锁定主线程并且可以取消的请求。

我们(至少)有 2 个 HTTP 库可供选择,java.net.*(例如 HttpURLConnection)和 org.apache.http.* 也无济于事。

对于最佳实践有什么共识吗?

【问题讨论】:

以前有人用过this 库吗?它看起来不错,但我不确定它如何处理失败的请求(或者即使它有效!) 查看以下链接以获得更简单的方法:masl.cis.gvsu.edu/2010/04/05/… 你愿意分享你的 HttpTask 类吗? 一点也不简单。此外,最佳实践是使用 AsyncTask 进行异步操作(HTTP 请求或其他)。 【参考方案1】:

android 1.5 SDK 引入了一个新类AsyncTask,旨在使在后台线程上运行任务并将结果传递给 UI 线程更简单一些。 Android Developers Blog 中给出的示例给出了如何使用它的基本思路:

public void onClick(View v) 
   new DownloadImageTask().execute("http://example.com/image.png");


private class DownloadImageTask extends AsyncTask 
   protected Bitmap doInBackground(String... urls) 
      return loadImageFromNetwork(urls[0]);
   

   protected void onPostExecute(Bitmap result) 
      mImageView.setImageBitmap(result);
   

doInBackgroundThread 方法在一个单独的线程上调用(由一个线程池化的ExecutorService 管理),并将结果传递给在 UI 线程上运行的onPostExecute 方法。您可以在 AsyncTask 子类上调用 cancel(boolean mayInterruptIfRunning) 来取消正在运行的任务。

至于使用java.netorg.apache.http 库进行网络访问,这取决于您。我发现java.net 库在简单地尝试发出GET 并阅读结果时使用起来非常愉快。 org.apache.http 库将允许您使用 HTTP 做几乎任何您想做的事情,但它们可能有点难以使用,我发现它们在简单的 GET 请求中表现不佳(在 Android 上)。

【讨论】:

谢谢。我实际上已经找到了 AsyncTask(在 1.5 中)和 UserTask(对于 1.1)并编写了一个通用的 HttpTask。几乎我唯一要做的就是弄清楚如何在请求处于活动状态时处理屏幕旋转。 对于阅读此答案的新用户:当心。这是对复杂问题的快速而肮脏的修复。正如 Snicolas 在他的回答中指出的那样,它存在缺陷和错误。处理多个并发任务的方式也不一致(developer.android.com/reference/android/os/AsyncTask.html)。在 Honeycomb 中,所有任务都将在单个线程上执行 - 这意味着您不会并行实现多个 HTTP 调用,除非您特别要求 THREAD_POOL_EXECUTOR 并实现所需的并发管道。【参考方案2】:

实际上,AsyncTask 的设计存在一些缺陷,使其无法真正用于网络。一个简单的例子是,您将失去 AsyncTask 和 Activity 之间的链接……只需旋转您的设备。

看看this thread:你会发现AsyncTask也很容易造成内存泄漏。

AsyncTask 文档清楚地说明了这一点:AsyncTask 应该只用于短期任务,而且很明显,网络不属于该类别。

所以,我真的建议你看看RoboSpice。这个库是为异步网络设计的,它是一种非常健壮的实现方式。 如果您只有几秒钟的时间可以说服,请查看此inforgraphics。

RoboSpice 也是商店中的演示应用程序:RoboSpice Motivations,它将深入解释有关 Android 上的异步网络的所有内容。

【讨论】:

我认为您对 Google 打算使用 AsyncTask 的目的是错误的。他们将“短期任务”定义为“最多几秒钟”(developer.android.com/reference/android/os/AsyncTask.html),并且确实给出了一个执行从 URI 下载文件的代码示例。 下载时您是否尝试旋转设备?事实上,有几个问题,但也有几个解决方法。问题是它们往往非常复杂,难以正确实现,而且代码不可重用。例如,我建议您查看商店中的 RoboSpice 动机。 (迂腐:)我仍然认为您对 Google 所宣扬的内容是错误的。这很可怕 - 因为 还认为 AsyncTask 不适合 HTTP 请求。现在更是如此,在按照您的建议测试了旋转我的设备和动机应用程序之后。 edit:是您的句子“AsyncTask 文档对此很清楚”引发了我的评论,因为我不同意。 顺便说一句,您检查过 Android 异步 Http 客户端 (loopj.com/android-async-http),您能说说它与 Robospice 相比如何吗? 不,但欢迎进行比较。顺便说一句,cmets 开始难以阅读。如果我们同意 AsyncTasks 不适合网络这一事实,我们应该这么说。【参考方案3】:

AsyncTask 引用托管在 Activity 或其他 Fragment 中的 静态保留 Fragment(没有 UI)怎么办?没有内存泄漏,在单独的线程中优雅的异步操作,没有对象引用丢失。

我认为这对于 http 请求是可以的,但对于文件上传/下载则不行。仔细看,有一句话:

如果您需要保持线程长时间运行,强烈建议您使用 java.util.concurrent 包提供的各种 API,例如 Executor、ThreadPoolExecutor 和 FutureTask。

但他们没有提到,带有单独线程的service 也可能是一个不错的选择。这意味着无论用户做什么,都将继续在后台执行任务。 (例如,如果他上传了一些文件,你不想因为他离开活动而停止)

此link 用于示例 - 找到 RetainedFragment.java

此 link 用于 AsyncTask。

【讨论】:

这个问题已经过时了,我希望没有人认为它与现代状况有关。在过去的几年里,已经有很多图书馆解决了这个问题。【参考方案4】:

您可以使用适用于 Android 的异步任务。要发出 http 请求,您可以使用 HttpURLConnection 类。

【讨论】:

以上是关于在 Android 中发出异步 HTTP 请求是不是有公认的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章

在 Android 中发出异步 HTTP 请求是不是有公认的最佳实践?

OkHttp 在 Android 中怎么发送异步请求

向具有不同域和基本身份验证的服务器发出 ajax POST 请求是不可能的吗?

Spring DeferredResult 异步请求

如何在android中同步/限制某些异步http调用

ajax小总结