Asynctask、Thread、Services和Loader的比较

32

我对在 Android 中使用 AsynctaskThreadServiceLoader 之间的区别有些困惑。

我知道它们如何工作,但仍然不明白应该在什么情况下使用它们。

我已经使用 Android 工作了 3 年,通常仍然使用 AsyncTask 处理所有后台任务(有时也使用 Thread)。但是许多人认为 "Asynctask 已过时",并且不建议使用它们。他们推荐使用 robospice 或 Volley。

那么,AsyncTask 真的很糟糕吗?是否应该使用网络任务框架?而对于后台(非网络)任务,我应该使用什么呢?


我使用了一个来自Java框架的执行器。 - Blackbelt
6个回答

25

线程:与Java线程相同,用于执行大型操作,但您必须自行管理它,并且可能会导致同步问题。在非UI线程上运行时,无法更新UI。

AsyncTask:一款在Android中可用的优秀线程库,用于执行后台任务。它由安卓操作系统自己管理,您可以从中更新UI。它根据安卓版本并行或串行运行。有时使用它可能会很混乱,例如在方向更改的情况下,现在您可以使用比AsyncTask更好的Volley进行网络调用。AsyncTasks不关心它们的父活动是否正在运行,有时取消它们可能会非常繁琐。因此,如果您正在使用AsyncTask进行REST API调用,我建议您使用RETROFITVOLLEY,如果您在两者之间选择RETROFIT,我建议您再看看来自Square的另一个令人惊叹的图像加载库PICASSO

服务:如果要执行长期的后台任务,您应该使用服务。如果需要,您可以将服务绑定到活动。您可以定义它们在相同的线程或不同的线程中运行,并且您需要在清单中声明它,或者您可以使用IntentService - 一种在其自己的线程中运行的服务变体,但在使用之前要小心,不要用于长时间运行的任务。它是一个单次操作。如果您打算使用服务,请评估哪种类型的服务更适合您的要求,普通服务还是IntentService。

加载器:这与AsyncTask在许多方面相同,建议在片段中使用加载器,并解决了异步任务的方向问题。

如果您已经转移到kotlin,我建议您看一下Coroutines。它们非常轻量级且对线程提供了相当有效的控制,并为您提供了大量的生命周期控制。


20
AysncTasks并不是‘过时’,而更多地是‘不完整’。异步任务不会在意它们的父活动当前是否正在运行,这就是为什么需要检查上下文是否为null或不为null的原因。此外,除非您使用自己的线程池执行器,否则这些任务会按顺序执行。
Volley试图填补这些差距,主要涉及与主线程同步和线程池。如果您希望执行需要平均网络请求的任务(如某些元数据列表和图片[例如YouTube应用程序请求和Facebook应用程序请求]),则它的表现最佳。
通常,Volley的几个优点如下:
1. 它使工作线程了解活动(主线程)的情况 2. 更易于资源优先级排序,您可以为您的下载请求提供优先级。典型的场景涉及将文本的优先级高于图像。 3. 有效的请求缓存和内存管理。 4. 可扩展性 5. 它为您提供一种在活动关闭或重新启动时放弃请求的选项。 6. 与AsyncTasks相比,更简单的数据检索模式。
当涉及流媒体请求/视频时,Volley表现不佳,正如Google I/O所述。
我不太了解Robospice。 附注:如果你有时间,请看一下https://www.youtube.com/watch?v=yhv8l9F44qo 如果你想了解其他类库的基准测试,可以阅读以下内容:Comparison of Android networking libraries: OkHTTP, Retrofit, and Volley

4
无论您使用何种抽象概念,它都可以归结为一个“线程”。因此,每个 Android 的异步/并行类在幕后都使用“线程”/“执行器”,并具有与线程相同的潜在问题,如锁定。
它们之间的区别在于用途不同。“AsyncTask” 例如定义了一个方便的完成回调函数,“onPostExecute()”。而“CountDownTimer” 可以帮助您控制时间等等。
当然,您也可以使用普通的“线程”,但在这种情况下,您需要花更多的时间来自己解决可能出现的问题。
因此,安卓为您提供了一些正确的工具来做正确的工作。

3
但很多人说"Asynctask已过时",不建议使用它们。 我还没有遇到有人这样说。但是,决定框架的哪个部分已过时或已弃用是Android团队的工作。CursorLoaders使用AsyncTaskLoader,后者使用AsyncTask。AsyncTasks是一种抽象,可以防止开发人员实现令人讨厌的Thread状态逻辑。这意味着所有这些类反过来都在后台使用Threads。
那么,Asynctask真的很糟糕,我应该使用框架来处理网络任务吗?而对于后台(非网络)任务,我应该使用什么?
关键在于了解何时以及如何使用您的工具。您提到了CursorLoader。在这种特定情况下,当您阅读文档并稍微尝试一下时,您会意识到它有意与ContentProviders平滑集成。现在,ContentProviders抽象了底层数据;您可以查询本地SQLite数据库或远程服务器。
通常,AsyncTasks被用于检索简洁的、不太大的信息(在与服务器交互时)。人们可能会说AsyncTasks已经过时了,因为有更好(更高效)的与服务器交互的方法(参见Retrofit)。

3

我认为AsyncTaskThread更好,因为它提供了在主线程上的回调。而LoaderAsyncTask更好,因为它还会帮你处理配置更改。


2

AsyncTask

AsyncTask 可以使 UI 线程的使用更加合理和便捷。它允许你在后台执行操作并在 UI 线程上发布结果,而无需操纵线程和/或处理程序。

AsyncTask 旨在成为 Thread 和 Handler 的辅助类,不构成通用的线程框架。 AsyncTasks 应该理想地用于短时间操作(最多几秒钟)。

如果需要长时间运行的线程,请强烈建议使用 java.util.concurrent 包提供的各种 API,例如 ExecutorThreadPoolExecutorFutureTask

Thread

将许多或长时间的任务从主线程中移出,以便它们不会干扰平滑渲染和对用户输入的快速响应,这是您采用线程的最大原因。

使用它将长时间运行的计算与主线程(UI 线程)分离。

Service

Service 是一个应用程序组件,可以在后台执行长时间运行的操作,并且不提供用户界面。

服务可以处理网络事务、播放音乐、执行文件 I/O 或与内容提供者交互,都是在后台完成的。

IntentService

IntentService 是处理按需异步请求(表示为 Intents)的服务的基类。

所有请求都在单个工作线程上处理-它们可能需要尽可能长的时间(并且不会阻塞应用程序的主循环),但一次仅处理一个请求。

Loader

Loader API 允许你从内容提供者或其他数据源加载数据,以在 Activity 或 Fragment 中显示。

Loaders 解决了这些问题,并包括其他好处。例如:

  1. Loaders 在单独的线程上运行,以防止 UI 卡顿或无响应。

  2. Loaders 通过提供回调方法来简化线程管理,当事件发生时进行回调。

  3. Loaders 在配置更改时持久缓存结果,以防止重复查询。
  4. Loaders 可以实现观察者以监视底层数据源中的更改
所以,Asynctask真的很糟糕,我应该使用网络任务框架吗?那么对于后台(非网络)任务,我应该使用什么?
对于持续时间短于5ms的工作项,请使用AsyncTask。您可以使用ThreadServiceIntentService来处理后台任务。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接