Подтвердить что ты не робот

Использование Android concurrency

Android имеет множество разных способов одновременного выполнения кода на отдельных потоках. Но я не уверен, когда каждый из них следует использовать или какие лучшие практики для этих разных способов.

  • Когда/Почему следует использовать обработчики?

  • Когда/Почему должны использоваться Loaders?

  • Когда/Почему следует использовать AsyncTasks?

  • Когда/Why следует использовать FutureTask?

  • Когда/Зачем использовать Исполнитель?

  • Когда/зачем использовать Threads/Runnables?

  • Когда/Почему должен использоваться Волейл?

Я пропустил какой-нибудь?

Большое спасибо за помощь!

4b9b3361

Ответ 1

У вас есть довольно большой список компонентов, каждый из которых адресует несколько разные вещи. Два основных конфликта в моем опыте - это фактически между обработчиками и исполнителями, а также задачи против потоков.

Обзор

Темы

Потоки являются основным системным механизмом, используемым для облегчения concurrency. Темы существуют в Windows, Unix и т.д., И могут быть реализованы каким-либо образом система сочтет нужным. Обычно довольно сложно создавать потоки (и тем более создавать совершенно новые процессы). Я не знаю, использует ли Dalvik VM поток Linux или предоставляет свою собственную реализацию Thread. В соответствии с этим Документ архитектуры виртуальной машины Dalvik, Dalvik VM просто использует модель потоков Linux для реализации потока. Однако Dalvik VM не соответствует модели памяти Java Language Specification до Android 4.0.

Как вы, возможно, знаете, потому что это дорого для создания потоков, лучший способ запланировать множество асинхронных вычислений - использовать управляемый пул потоков (размер в зависимости от возможностей вашего основного оборудования) и просто передать задачи менеджер, который, в свою очередь, планирует выполнение задач по потокам по мере их появления.

Обработчики Android

Краткий обзор истории, как я понимаю, заключается в том, что разработка Android началась еще в те дни, когда библиотеки Java Executor/api стали затвердевшими. Чтобы обеспечить менее запутанный интерфейс concurrency, чем существующие методы Threads and Synchronization, и облегчить передачу сообщений между потоками в приятной манере, Android представил Handlers. Однако, если я не понимаю это неправильно, Handlers - это в основном то же самое, что и Executors. Вы передаете сообщения (содержащие Runnables) или просто Runables, для Handlers, и эти сообщения попадают в очередь и выполняются так же быстро, как Thread Handler.

Исполнители Java

В Android вся связь между потоками выполняется (или должна быть) с помощью обработчика потоков (насколько мне известно и исключая ситуации, когда вы напрямую обращаетесь к другой памяти потоков, и может потребоваться синхронизация). В новой Java Executors функционально эквивалентны Handlers, а FutureTasks эквивалентны сообщениям. Runnables - все еще Runnables. Runnable используется, когда код просто необходимо выполнить. FutureTask используется, когда вычисление должно выполняться асинхронно, и результат должен быть извлечен из вычисления. Результат может быть любым объектом. Поскольку FutureTask реализует интерфейс Future, вы также можете легко подождать в одном потоке для будущего, чтобы решить и получить результат.

Погрузчики

Погрузчики - это просто попытка обеспечить механизм многократного использования для загрузки данных (потребляемых активностью). Несмотря на документацию, класс Loader не является абстрактным, и он не должен использоваться исключительно для асинхронного сбора данных (хотя я не могу придумать случай, когда вы будете использовать его для синхронной загрузки, я не изучил это), AsyncTaskLoader просто использует AsyncTask для выполнения методов Loader, ответственных за загрузку данных. Погрузчики вообще не нужны.

Примеры

Темы

Потоки должны использоваться для поддержки исполнителей или обработчиков, или, в других случаях, вы будете знать, когда вам нужен поток (например, чтобы вернуть службу). Как правило, вы избегаете Threads для небольших задач, которые создаются, выполняются и уничтожаются либерально.

Обработчики против исполнителей

По моему опыту, лучше придерживаться Handlers при работе с сообщением, проходящим между вашим потоком пользовательского интерфейса (работа с иерархией Activity и/или View) и некоторым другим потоком. Однако при реализации собственных асинхронных функций кажется совершенно безопасным использование либо исполнителей, либо обработчиков. Например, у меня может быть класс, который управляет очередью изображений, получаемых с сервера. Я могу просто создать свой собственный исполнитель и передать задачи этому исполнителю, как я считаю нужным. Но при передаче сообщения сообщения обратно в Activity, которое загрузилось одним из изображений, и представление должно быть задано с результирующими данными, у меня были лучшие результаты с помощью обработчика активности (доступ через метод runOnUiThread()) в противоположность для создания исполнителя, который работает в потоке активности и размещения на нем Runnables. Непонятно, почему последний не работал все время (из документации, то есть), но я подозреваю, что это может привести к поведению, аналогичному методу Handler runWithScissors(). (Edit, теперь я знаю, что очень плохой практикой запускать несколько параллельных "петлеров" в одном потоке - так что это объясняет.)

Я думаю, что хорошее эмпирическое правило может быть:

  • Используйте обработчики при передаче сообщений между компонентами Android.
  • Используйте исполнителей или обработчиков при реализации собственной библиотеки или функциональных возможностей.

Runnables vs FutureTasks vs AsyncTasks

Как указывалось ранее, Runnables - это простой интерфейс, используемый для передачи вычислений между объектами. Вам не нужно использовать Runnables только тогда, когда задействованы потоки/исполнители/обработчики - их можно использовать для захвата состояния и повторного использования кода.

  • Runnables и FutureTasks используются с Executors.
  • AsyncTasks (неявно) используются с обработчиками. Когда вы создаете AsyncTask, вы предоставляете ссылку на активность, а класс AsyncTask облегчает выполнение метода doInBackground в одном потоке из пула рабочих потоков (это внутренне управляется Исполнителем). Для этого обработчик используется для передачи сообщений между потоком активности и потоком задачи. Однако сама задача управляется Исполнителем и передается в рабочий поток, когда он доступен.

Погрузчики

Я не использую Loaders. Но они могут использоваться, когда у вас есть данные, которые необходимо загрузить для того, чтобы Activity использовал его. Вы можете использовать CursorLoader с ContentProvider, если вы выполняете идиому ContentProvider с точки зрения обработки данных.

Volley

Я никогда не использовал залп, поэтому я сомневаюсь, что у меня есть полезная информация на этом канале.


Отказ от ответственности: я не являюсь авторитетом в истории Android. Несмотря на это, я надеюсь, что обзор поможет добавить ясность.