Обработчик против AsyncTask против потока
Я немного запутался в различиях между ними.Handlers
, AsyncTask
и Threads
в Android. Я прочитал довольно много блогов и вопросов здесь, в stackoverflow.
Handler
это фоновые потоки, которые обеспечивают взаимодействие с пользовательским интерфейсом. Обновление progressbar, например, должно быть сделано через Handler
. Используя обработчики, вы получаете преимущество MessagingQueues
, так что если вы хотите запланировать сообщения или обновить несколько элементов пользовательского интерфейса или иметь повторяющиеся задачи.
AsyncTask
похожи, Инфакт они используйте Handler
, но не запускается в потоке пользовательского интерфейса, поэтому он хорош для извлечения данных, например, для извлечения веб-служб. Позже вы можете взаимодействовать с пользовательским интерфейсом.
Thread
однако вы не можете взаимодействовать с пользовательским интерфейсом, обеспечить более "базовую" потоковую обработку, и вы пропустите все абстракции AsyncTask
.
Однако я хотел бы иметь соединение сокета, выполняемое в службе. Должен ли он выполняться в обработчике или потоке, или даже в AsyncTask
? Взаимодействие с пользовательским интерфейсом вовсе не обязательно. Имеет ли это значение для вас? условия исполнения, которые я использую?
12 ответов:
Как говорится в учебнике по фоновой обработке Android с обработчиками, AsyncTask и загрузчиками на сайте Vogella:
Класс
Handler
может использоваться для регистрации в потоке и обеспечивает простой канал для отправки данных в этот поток.Класс
AsyncTask
инкапсулирует создание фонового процесса и синхронизацию с основным потоком. Он также поддерживает отчеты о ходе выполнения задач.И
Thread
в основном является основным элементом многопоточности, которую разработчик может использовать со следующим недостатком:Если вы используете потоки Java, вы должны выполнить следующие требования в вашем собственном коде:
- синхронизация с основным потоком, если вы возвращаете результаты в пользовательский интерфейс
- Нет по умолчанию для отмены потока
- Нет пула потоков по умолчанию
- Нет по умолчанию для обработки изменений конфигурации в Android
И что касается
AsyncTask
, Как говорится в ссылке разработчика Android :
AsyncTask
обеспечивает правильное и простое использование потока пользовательского интерфейса. Этот класс позволяет выполнять фоновые операции и публиковать результаты в пользовательском интерфейсе поток без необходимости манипулировать потоками и / или обработчиками.
AsyncTask
предназначен для того, чтобы быть вспомогательным классом вокругThread
иHandler
и не представляет собой общую структуру потоков. AsyncTasks в идеале следует использовать для коротких операций (несколько секунд на наибольший.) Если вам нужно держать потоки запущенными в течение длительного периода времени, настоятельно рекомендуется использовать различные API, предоставляемые Ява.утиль.параллельный пакет, такой как Executor, ThreadPoolExecutor и FutureTask.Обновление май 2015: я нашел отличную серию лекций, охватывающую эту тему.
Это поиск Google: Дуглас Шмидт лекция Android параллелизм и синхронизация
Это видео первой лекции на YouTube
Все это является частью CS 282 (2013): системное программирование для Android из Университета Вандербильта. Вот плейлист YouTube
Дуглас Шмидт, кажется, быть отличным преподавателем
Важно: Если вы находитесь в точке, где вы планируете использовать
AsyncTask
для решения ваших проблем с потоками, вы должны сначала проверитьReactiveX/RxAndroid
для возможно более подходящего шаблона программирования. Очень хорошим ресурсом для получения обзора являетсяизучение RxJava 2 для Android на примере .
Если вы посмотрите на исходный код
Таким образом, нет никакой магии вAsyncTask
иHandler
, вы увидите, что их код написан исключительно на Java. (Конечно, есть и исключения, но это не главное.)AsyncTask
илиHandler
. Они просто облегчают вашу работу в качестве разработчика.Например: если программа A вызывает метод A (), метод A () может выполняться в другом потоке с программой A. Вы можете легко проверить это с помощью:
Thread t = Thread.currentThread(); int id = t.getId();
Почему вы должны использовать новую нить? Вы можете поищите в гугле. Много-много причин.
Итак, в чем же разница между
Thread
,AsyncTask
, иHandler
?
AsyncTask
иHandler
написаны на Java (внутренне они используютThread
), поэтому все, что вы можете сделать сHandler
илиAsyncTask
, Вы можете достичь с помощьюThread
тоже.Что может
Наиболее очевидной причиной является связь между вызывающим потоком и рабочим потоком. (вызывающий поток: поток, вызывающий работника Поток для выполнения некоторой задачи. Вызывающий поток не обязательно должен быть потоком пользовательского интерфейса). Конечно, вы можете общаться между двумя потоками другими способами, но есть много недостатков (и опасностей) из-за проблем безопасности потока.Handler
иAsyncTask
реально помочь вам?, который является, почему вы должны использовать
Handler
иAsyncTask
. Они делают большую часть работы за вас, вам просто нужно знать, какие методы переопределить.Разница между
Handler
иAsyncTask
заключается в следующем: используйтеAsyncTask
, когда вызывающий поток является UI Нить . Вот что говорится в документе android:AsyncTask обеспечивает правильное и простое использование потока пользовательского интерфейса. Этот класс позволяет выполнять фоновые операции и публиковать результаты в пользовательском интерфейсе поток без необходимости манипулировать потоками и / или обработчиками
Я хочу подчеркнуть два момента:
1) простота использования потока пользовательского интерфейса (таким образом, используйте, когда вызывающий поток является потоком пользовательского интерфейса).
2) нет необходимости манипулировать обработчиками. (означает: вы можете использовать обработчик вместо этого AsyncTask, но AsyncTask-более простой вариант).В этом посте есть много вещей, которые я еще не сказал, например: что такое UI Thread, или почему это проще. Вы должны знать какой-то метод за каждым видом и использовать его, вы полностью поймете, почему..
@: когда вы прочтете документ Android, вы увидите:
Обработчик позволяет отправлять и обрабатывать сообщения и запускаемые объекты связанный с MessageQueue потока
Они могут показаться странным на первый взгляд. Просто поймите, что у каждого потока есть каждая очередь сообщений (например, список дел), и поток будет принимать каждое сообщение и делать это, пока очередь сообщений не опустеет (так же, как вы заканчиваете свою работу и ложитесь спать). Поэтому, когда
Handler
связывается, он просто дает сообщение потоку вызывающего объекта, и он будет ждать обработки. Сложно? Просто помните, чтоHandler
может безопасно взаимодействовать с вызывающим потоком.
После того, как вы посмотрите в глубину, это прямо вперед.
AsyncTask
:Это простой способ использовать поток , ничего не зная о модели потока java.
AsyncTask
дает различные обратные вызовы, соответствующие рабочему потоку и основному потоку.Используйте для небольших операций ожидания, таких как:
- извлечение некоторых данных из веб-служб и отображение поверх макета.
- запрос к базе данных.
- Когда вы осознаете, что запущенная операция никогда, никогда не будет вложенным.
Handler
:Когда мы устанавливаем приложение в android, то оно создает поток для этого приложения под названием MAIN UI Thread. Все действия выполняются внутри этого потока. По правилу Android single thread model мы не можем получить доступ к элементам пользовательского интерфейса (bitmap, textview и т. д..) непосредственно для другого потока, определенного внутри этого действия.
Обработчик позволяет вам взаимодействовать с потоком пользовательского интерфейса из другого фонового потока. Это полезно в android, поскольку android не позволяет другим потокам напрямую взаимодействовать с потоком пользовательского интерфейса. Обработчик может отправлять и обрабатывать сообщения и запускаемые объекты, связанные с MessageQueue потока. Каждый экземпляр обработчика связан с одним потоком и очередью сообщений этого потока. При создании нового обработчика он привязывается к потоку / очереди сообщений потока, который его создает.
Он лучше всего подходит для:
- это позволяет вам делать очередь сообщений.
- сообщение планирование.
Теперь пришло время поговорить о нитях.
Thread
:Поток является родителем как
AsyncTask
, так иHandler
. Они оба внутренне используют поток, что означает, что вы также можете создать свою собственную модель потока, какAsyncTask
иHandler
, но это требует хорошего знания многопоточной реализации Java.
AsyncTask
используется для выполнения некоторых фоновых вычислений и публикации результата в потоке пользовательского интерфейса (с дополнительными обновлениями хода выполнения). Поскольку вы не связаны с UI, тоHandler
илиThread
кажется более подходящим.Вы можете создать фон
Thread
и передать сообщения обратно в основной поток с помощью методаHandler
post
.
Android поддерживает стандартные Javaпотоки . Вы можете использовать стандартные потоки и инструменты из пакета "
java.util.concurrent
", чтобы поместить действия в фоновый режим. Единственное ограничение заключается в том, что вы не можете напрямую обновить пользовательский интерфейс из фонового процесса.Если вам нужно обновить пользовательский интерфейс из фоновой задачи, вам нужно использовать некоторые классы Android. Вы можете использовать класс "
android.os.Handler
" для этого или класса "AsyncTask
"Класс "
Handler
" может обновить пользовательский интерфейс. Дескриптор предоставляет методы для получения сообщений и для запускаемых объектов. Чтобы использовать обработчик, вы должны подклассировать его и переопределитьhandleMessage()
для обработки сообщений. Для обработкиRunable
, Вы можете использовать методpost();
вам нужен только один экземпляр обработчика в вашей деятельности.Поток может отправлять сообщения с помощью метода
sendMessage(Message msg)
илиsendEmptyMessage
.Если у вас есть
Activity
который необходимо загружать контент или выполнять операции, которые могут выполняться в фоновом режимеAsyncTask
позволяет поддерживать отзывчивый пользовательский интерфейс и публиковать ход выполнения этих операций для пользователя.Для получения дополнительной информации вы можете посмотреть на эти ссылки.
Http://mobisys.in/blog/2012/01/android-threads-handlers-and-asynctask-tutorial/
Http://www.slideshare.net/HoangNgoBuu/android-thread-handler-and-asynctask
На мой взгляд, потоки-не самый эффективный способ выполнения соединений сокетов, но они обеспечивают наибольшую функциональность с точки зрения выполнения потоков. Я говорю это потому, что по опыту, запуск потоков в течение длительного времени приводит к тому, что устройства становятся очень горячими и ресурсоемкими. Даже простой
while(true)
нагреет телефон за считанные минуты. Если вы говорите, что взаимодействие с пользовательским интерфейсом не важно, возможно,AsyncTask
хороши, потому что они предназначены для долгосрочных процессов. Это всего лишь мое мнение о оно.Обновить
Пожалуйста, не обращайте внимания на мой ответ выше!Я ответил на этот вопрос еще в 2011 году, когда у меня было гораздо меньше опыта в Android, чем сейчас. Мой ответ выше вводит в заблуждение и считается неправильным. Я оставляю его там, потому что многие люди прокомментировали его ниже, поправляя меня, и я усвоил свой урок.
Есть гораздо лучшие другие ответы на эту тему, но я, по крайней мере, дам более правильный ответ. Нет ничего плохого в использовании a обычная JavaThread
; Тем не менее, вы должны действительно быть осторожны о том, как вы реализуете его, потому что делать это неправильно может быть очень интенсивным процессором (наиболее заметным симптомом может быть нагрев вашего устройства).AsyncTask
s довольно идеальны для большинства задач, которые вы хотите выполнять в фоновом режиме (общие примеры-дисковый ввод-вывод, сетевые вызовы и вызовы базы данных). ОднакоAsyncTask
s Не следует использовать для особо длительных процессов, которые могут потребоваться после того, как пользователь закроет приложение или переведет свое устройство в режим ожидания. Я бы сказал, что в большинстве случаев все, что не относится к потоку пользовательского интерфейса, может быть обработано вAsyncTask
.
Thread
:Вы можете использовать new
Thread
для длительных фоновых задач, не влияя на поток пользовательского интерфейса. Из потока java вы не можете обновить поток пользовательского интерфейса.Поскольку обычная нить не очень полезна для архитектуры Android, были введены вспомогательные классы для потоковой обработки.
Вы можете найти ответы на свои запросы на странице документацииThreading performance .
A
Handler
позволяет отправлять и обрабатывать Сообщение иRunnable
объекты, связанные с потокомMessageQueue
. Каждый экземплярHandler
связан с одним потоком и очередью сообщений этого потока.Существует два основных применения для
Handler
:
Запланировать выполнение сообщений и исполняемых файлов как некоторую точку в будущем;
Чтобы поставить в очередь действие, которое будет выполняться в другом потоке, чем ваш собственный.
AsyncTask
обеспечивает правильное и простое использование потока пользовательского интерфейса. Этот класс позволяет выполнять фоновые операции и публиковать результаты в потоке пользовательского интерфейса без необходимости манипулировать потоками и/или обработчиками.Недостатки:
По умолчанию приложение помещает все объекты
AsyncTask
, которые оно создает, в один поток. Поэтому они выполняются последовательно, и, как и в случае с основным потоком, особенно длинный рабочий пакет может блокировать очередь. По этой причине используйте AsyncTask для обработки рабочих элементов короче чем 5 мс по длительности .
AsyncTask
объекты также являются наиболее распространенными нарушителями для неявных ссылок.AsyncTask
объекты также представляют риски, связанные с явными ссылками.Вам может понадобиться более традиционный подход к выполнению блока работы на более длинном работающем потоке ( в отличие от AsyncTask, который должен использоваться для рабочей нагрузки 5 мс) и некоторая возможность управлять этим рабочим процессом вручную. Один поток обработчика-это фактически продолжительный поток, который захватывает работу из очереди и работает с ней.
Этот класс управляет созданием группы потоков, устанавливает их приоритеты и управляет распределением работы между этими потоками. При увеличении или уменьшении рабочей нагрузки класс запускает или уничтожает больше потоков, чтобы приспособиться к рабочей нагрузке.Если нагрузка больше и одного
HandlerThread
недостаточно, вы можете перейти наThreadPoolExecutor
Однако я хотел бы иметь соединение сокета, выполняемое в службе. Должен ли он выполняться в обработчике или потоке, или даже в AsyncTask? Взаимодействие с пользовательским интерфейсом вовсе не обязательно. Имеет ли это значение с точки зрения производительности, которую я использую?
Поскольку взаимодействие с пользовательским интерфейсом не требуется, вы не можете использовать
AsyncTask
. Обычные потоки не очень полезны, и поэтомуHandlerThread
является лучшим вариантом. Так как вы должны поддерживать соединение с сокетом, обработчик на главном потоке не полезен при все. СоздайтеHandlerThread
и получитеHandler
от петлителяHandlerThread
.HandlerThread handlerThread = new HandlerThread("SocketOperation"); handlerThread.start(); Handler requestHandler = new Handler(handlerThread.getLooper()); requestHandler.post(myRunnable); // where myRunnable is your Runnable object.
Если вы хотите связаться с потоком пользовательского интерфейса, вы можете использовать еще один обработчик для обработки ответа.
final Handler responseHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { //txtView.setText((String) msg.obj); Toast.makeText(MainActivity.this, "Foreground task is completed:"+(String)msg.obj, Toast.LENGTH_LONG) .show(); } };
В вашем
Runnable
, Вы можете добавитьresponseHandler.sendMessage(msg);
Более подробную информацию о реализации можно найти здесь:
AsyncTask
предназначен для выполнения не более чем нескольких секунд операций, выполняемых в фоновом режиме (не рекомендуется для мегабайтов загрузки файлов с сервера или вычислительных задач с интенсивным ЦП, таких как операции ввода-вывода файлов ). Если вам необходимо выполнить длительную операцию, настоятельно рекомендуется использовать собственные потоки java. Java дает вам различные классы, связанные с потоками, чтобы сделать то, что вам нужно. ИспользуйтеHandler
для обновления потока пользовательского интерфейса.
позвольте мне попытаться ответить на этот вопрос с помощью примера:) - MyImageSearch [пожалуйста, обратитесь к изображению здесь главного экрана активности-содержащего кнопку редактирования текста / поиска / вид сетки]
Описание MyImageSearch - После того, как пользователь введет данные в поле редактировать текст и нажмет на кнопку Поиск, мы будем искать изображения в интернете с помощью веб-сервисов, предоставляемых flickr (вам нужно только зарегистрироваться там, чтобы получить ключ / секрет token) - для поиска мы посылаем запрос HTTP и получаем данные JSON обратно в ответ, содержащие url-адреса отдельных изображений,которые мы затем будем использовать для загрузки представления сетки.
Моя реализация - в основной деятельности я определить внутренний класс, который расширяет AsyncTask, чтобы отправить HTTP-запрос в doInBackGround метод и принести ответ JSON и обновление моего местного ArrayList с FlickrItems, который я собираюсь использовать, чтобы обновить GridView с помощью FlickrAdapter (расширяет BaseAdapter)и вызовите адаптер.notifyDataSetChanged () в onPostExecute () AsyncTask для перезагрузки представления сетки. Обратите внимание, что здесь HTTP-запрос является блокирующим вызовом, из-за которого я сделал это через AsyncTask. И, я могу кэшировать элементы в адаптере, чтобы увеличить производительность или хранить их на SD-карте. Сетка, которую я буду раздувать в FlickrAdapter, содержит в моей реализации панель прогресса и представление изображения. Ниже вы можете найти код для mainActivity, который я использованный.
Ответ на вопрос теперь - Таким образом, как только у нас есть данные JSON для выборки отдельных изображений, мы можем реализовать логику получения изображений в фоновом режиме с помощью обработчиков или потоков или AsyncTask. Здесь мы должны отметить, что поскольку мои изображения после загрузки должны отображаться в UI / main потоке, мы не можем просто использовать потоки, так как они не имеют доступа к контексту. В FlickrAdapter варианты, которые я мог придумать:
- выбор 1: Создать LooperThread [расширяет поток] - и продолжайте загрузка изображений последовательно в одном потоке, сохраняя этот поток открой [петлитель.loop ()]
- выбор 2: Используйте пул потоков и разместите runnable через myHandler, который содержит ссылку на мой ImageView, но так как представления в виде сетки повторно используются, снова может возникнуть проблема, где изображение в индексе 4 является отображается в индексе 9 [загрузка может занять больше времени]
- Выбор 3 [я использовал это]: используйте пул потоков и отправьте сообщение myHandler, содержащее данные, относящиеся к индексу ImageView и ImageView сам, так что при выполнении handleMessage () мы будем обновлять ImageView только в том случае, если currentIndex соответствует индексу изображения, которое мы попробовал скачать.
- выбор 4: Используйте AsyncTask для загрузки изображения в фоновом режиме, но здесь у меня не будет доступа к количеству потоков, которые я хочу в пул потоков и он варьируется в зависимости от версии android, но в Choice 3 я могу принять сознательное решение размер пула потоков в зависимости от используемой конфигурации устройства.
Вот исходный код:
Я надеюсь, что мой ответ, хотя и длинный, поможет понять некоторые из более тонких деталей.public class MainActivity extends ActionBarActivity { GridView imageGridView; ArrayList<FlickrItem> items = new ArrayList<FlickrItem>(); FlickrAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageGridView = (GridView) findViewById(R.id.gridView1); adapter = new FlickrAdapter(this, items); imageGridView.setAdapter(adapter); } // To avoid a memory leak on configuration change making it a inner class class FlickrDownloader extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { FlickrGetter getter = new FlickrGetter(); ArrayList<FlickrItem> newItems = getter.fetchItems(); // clear the existing array items.clear(); // add the new items to the array items.addAll(newItems); // is this correct ? - Wrong rebuilding the list view and should not be done in background //adapter.notifyDataSetChanged(); return null; } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); adapter.notifyDataSetChanged(); } } public void search(View view) { // get the flickr data FlickrDownloader downloader = new FlickrDownloader(); downloader.execute(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
public class RequestHandler { public String sendPostRequest(String requestURL, HashMap<String, String> postDataParams) { URL url; StringBuilder sb = new StringBuilder(); try { url = new URL(requestURL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(15000); conn.setConnectTimeout(15000); conn.setRequestMethod("POST"); conn.setDoInput(true); conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(os, "UTF-8")); writer.write(getPostDataString(postDataParams)); writer.flush(); writer.close(); os.close(); int responseCode = conn.getResponseCode(); if (responseCode == HttpsURLConnection.HTTP_OK) { BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); sb = new StringBuilder(); String response; while ((response = br.readLine()) != null){ sb.append(response); } } } catch (Exception e) { e.printStackTrace(); } return sb.toString(); } private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException { StringBuilder result = new StringBuilder(); boolean first = true; for (Map.Entry<String, String> entry : params.entrySet()) { if (first) first = false; else result.append("&"); result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); result.append("="); result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); } return result.toString(); } }
Handler
- является средством связи между потоками. В android он в основном используется для связи с основным потоком путем создания и отправки сообщений через обработчик
AsyncTask
- используется для выполнения длительно работающих приложений в фоновом потоке. С помощью nAsyncTask
можно выполнить операцию в фоновом потоке и получить результат в основном потоке приложения.
Thread
- это легкий процесс, позволяющий достичь параллелизма и максимальной загрузки процессора. В android вы можете использовать поток для выполнения действий, которые не касаются пользовательского интерфейса приложения
Поток
При запуске приложения создается процесс для выполнения кода. Чтобы эффективно использовать вычислительный ресурс, потоки могут быть запущены в процессе, так что несколько задач могут быть выполнены одновременно. Таким образом, потоки позволяют создавать эффективные приложения, эффективно используя процессор без простоя.
В Android все компоненты выполняются в одном так называемом основном потоке. Система Android ставит задачи в очередь и выполняет их одну за другой в главном потоке. При длительном беге задачи выполняются, приложение перестает отвечать на запросы.
Чтобы предотвратить это, можно создавать рабочие потоки и выполнять фоновые или длительные задачи.
Обработчик
Поскольку android использует однопоточную модель, компоненты пользовательского интерфейса создаются не потокобезопасными, то есть только созданный поток должен получить к ним доступ, что означает, что компонент пользовательского интерфейса должен обновляться только в главном потоке. Поскольку компонент пользовательского интерфейса выполняется в основном потоке, задачи, выполняемые в рабочих потоках, не могут изменять компоненты пользовательского интерфейса. Это где Хэндлер входит в картину. Обработчик с помощью Looper может подключиться к новому потоку или существующему потоку и запустить код, который он содержит на подключенном потоке.
ОбработчикДелает возможным межпотоковое взаимодействие. Используя обработчик, фоновый поток может отправлять ему результаты, а обработчик, подключенный к основному потоку, может обновлять компоненты пользовательского интерфейса в основном потоке.
AsyncTask
AsyncTask, предоставляемый android, использует как поток, так и обработчик, чтобы сделать запуск простых задач в фоновом режиме и обновление результатов из фонового потока в основной поток легко.
См. ветке андроид, обработчик, asynctask и потоки для примера.