Asynctask vs 线程 vs 服务 vs 加载器

Posted

技术标签:

【中文标题】Asynctask vs 线程 vs 服务 vs 加载器【英文标题】:Asynctask vs Thread vs Services vs Loader 【发布时间】:2014-08-30 08:23:22 【问题描述】:

我对 androidAsynctaskThreadServiceLoader 之间的区别感到有些困惑。

我知道它是如何工作的。但我仍然不明白我应该使用什么以及何时使用。

我在 Android 上工作了 3 年,并且通常仍将 AsyncTask 用于所有后台任务(有时是线程)。但是很多人说“Asynctask 已经过时”,不推荐使用。他们还建议使用 robospice 或 Volley。

那么,AsyncTask 真的那么糟糕,我应该使用框架来完成网络任务吗?我应该将什么用于后台(不是网络)任务?

【问题讨论】:

我使用一个执行器,来自 java 框架 相关线程 - Difference between Service, Async Task & Thread? 【参考方案1】:

线程:与 Java 线程相同,使用它来执行繁重的操作,但您必须自己管理它,它还会导致同步问题,并且您无法从中更新 UI,直到您在 UI 线程上运行它.

AsyncTask:Android 中用于执行后台任务的出色线程库。它由 android 操作系统本身管理,您可以从中更新 UI。它可以并行或串行运行,具体取决于 android 的版本。有时在方向变化的情况下使用它可能会很麻烦,现在为了进行网络调用,您可以使用比AsyncTask 更好的 volley。 AsyncTasks 不关心他们的父活动是否正在运行,有时取消它可能非常乏味。所以,如果你使用 AsyncTask 来更好地调用其他 API,我建议你使用 RETROFIT 或 VOLLEY,如果你在两者之间选择 RETROFIT,我建议你看看 PICASSO 另一个很棒的来自 square 的库用于图像加载。

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

Loaders:这在很多方面与AsyncTask 相同,建议使用带有片段的loaders,它解决了异步任务的方向问题。

如果您已经迁移到 kotlin,我建议您查看 Coroutines。这些非常轻量级且对线程非常有效,并为您提供了对生命周期的大量控制。 我希望这会有所帮助。

【讨论】:

【参考方案2】:

AysncTask 并不像 不完整那样“过时”。 除其他事项外,异步任务不会打扰其父活动当前是否正在运行。出于同样的原因,您包括检查以验证上下文是否为空。此外,除非您使用自己的线程池执行器,否则这些任务会串行执行。

Volley 试图填补这些空白,主要涉及与主线程和线程池同步。如果您想做需要平均网络请求的事情,它会表现得最佳;像一些元数据列表和图像(图片 youtube 应用程序请求和 facebook 应用程序请求的帖子)。

Volley 的典型优势如下:

    它让工作线程了解活动(主线程) 您可以为下载请求提供更轻松的资源优先级。 一个典型的场景是您优先考虑文本而不是图像。 有效的请求缓存和内存管理。 可扩展 它为您提供了一个选项,可以在您的活动被关闭或重新启动时放弃您的请求。 与 AsyncTask 相比,数据检索模式更简单。

在 Google I/O 上提到的流式传输请求/视频方面,Volley 表现不佳。

我并不完全了解 robospice。 ps:如果你手头有时间看https://www.youtube.com/watch?v=yhv8l9F44qo

如果您希望进入其他具有相同基准的库,请阅读此处进一步阅读。 Comparison of Android networking libraries: OkHTTP, Retrofit, and Volley

【讨论】:

【参考方案3】:

你使用什么抽象并不重要,它归结为Thread。因此,Android 的每个异步/并行类都在幕后使用Thread/Executor,并且具有与线程完全相同的潜在问题,例如锁定。

then 的区别在于它的用法。例如,AsyncTask 定义了一个方便的完成回调 - onPostExecute()CountDownTimer 可以让你控制时间等等。

您当然可以使用普通的Thread,但在这种情况下,您必须投入更多时间来自己发现可能出现的问题。

因此,Android 为您提供了一些适合工作的工具。

【讨论】:

【参考方案4】:

但是很多人说“Asynctask 已经过时”,不推荐使用。

我没有遇到过这样说的人。但决定框架的某些部分何时过时或弃用是 Android 团队的工作。 CursorLoaders 使用 AsyncTaskLoader,它使用 AsyncTaskAsyncTasks 是一种抽象,可防止开发人员不得不实现讨厌的 Thread 状态逻辑。这意味着所有这些类在后台依次使用 useThreads

那么,Asynctask 真的那么糟糕吗?我应该使用框架 网络任务?我应该用什么作为背景(不是 网络)任务?

关键在于了解何时以及如何使用您的工具。你提到CursorLoader。在这种特殊情况下,当您阅读文档并稍微使用它时,您会意识到它故意与ContentProviders 平滑集成。现在,ContentProviders 抽象底层数据;您可以查询本地 SQLite 数据库或远程服务器。

通常,AsyncTasks 用于检索简洁的“不太大”信息片段(用于与服务器通信时)。人们可能会说AsyncTasks 已经过时了,因为有更好(更高效)的方式与服务器交互(参见Retrofit)。

【讨论】:

【参考方案5】:

我认为AsyncTaskThread 更好,因为它在主线程上提供回调。 LoaderAsyncTask 更好,因为它还为您处理配置更改。

【讨论】:

【参考方案6】:

AsyncTask:

AsyncTask 允许正确且轻松地使用 UI 线程。此类允许您执行后台操作并在 UI 线程上发布结果,而无需操作线程和/或处理程序。

AsyncTask 被设计为围绕 Thread 和 Handler 的辅助类,并不构成通用的线程框架。 AsyncTasks 最好用于短时间操作(最多几秒钟。)

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

Thread:

从主线程中移动大量或较长的任务,以便它们不会影响流畅的渲染和对用户输入的快速响应,这是您在应用中采用线程的最大原因。

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

Service:

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

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

IntentService:

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

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

Loader:

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

装载机解决了这些问题并带来了其他好处。例如:

    加载程序在单独的线程上运行,以防止 UI 出现卡顿或无响应。

    加载器通过在事件发生时提供回调方法来简化线程管理。

    加载程序会在配置更改时保持并缓存结果,以防止重复查询。 加载器可以实现一个观察者来监控底层数据源的变化

那么,Asynctask 真的那么糟糕,我应该使用框架来完成网络任务吗?我应该将什么用于后台(不是网络)任务?

使用AsyncTask 处理持续时间短于 5 毫秒的工作项。后台任务可以使用ThreadServiceIntentService

【讨论】:

以上是关于Asynctask vs 线程 vs 服务 vs 加载器的主要内容,如果未能解决你的问题,请参考以下文章

用于从 BlockingCollection 消费的计时器 vs 线程 vs RegisteredWaitHandle

异步方法中的 Await vs Task.Result [重复]

多进程 vs 多线程

一文看懂 Mutex vs Semaphore vs Monitor vs SemaphoreSlim

进程vs线程

Apache vs. Nginx