#java #android #ui-thread
#java #Android #пользовательский интерфейс-поток
Вопрос:
Я знаю, что ни один поток не может получить доступ к текущему представлению, если это не поток пользовательского интерфейса. Мне интересно, почему? Почему так важно, какой поток изменяет представление? Это причина безопасности? Это обходной путь, который я использую:
public void doLayout()
{
Runnable run = new Runnable()
{
public void run()
{
ViewerActivity.setContentView(R.layout.main);
}
};
handler.post(run);
}
private Handler handler;'
Это довольно сложно делать каждый раз, когда я хочу изменить макет. Есть ли другая работа? Я знаю об асинхронной задаче, и я так и не нашел хорошего способа ее использования, это лучше, чем то, что я делаю? Все соответствующие ответы оценены!
Комментарии:
1. Вам следует подробнее прочитать о блокировке / синхронизации в Java (т. Е. Когда использовать «синхронизированный») — как только вы это поймете, станет очевидно, почему вам нужно прыгать через обручи, чтобы взаимодействовать с потоком пользовательского интерфейса из отдельного потока.
2. Причина разделения заключается в том, чтобы избежать взаимоблокировок. Предположим, например, что вам было разрешено свободно изменять представление из любого потока. Давайте представим, что вы выполняете вызов DB. Итак, вы получаете обработчик для компонента представления, затем запрашиваете базу данных, но база данных блокирует и впоследствии блокирует текущий поток. Теперь поток пользовательского интерфейса также будет заблокирован, поскольку вы находились в процессе изменения представления, и ему нужно дождаться его освобождения, прежде чем он сможет безопасно продолжить. Это создало бы действительно плохие программы, которые в конечном итоге заблокировали бы намного больше, чем в настоящее время.
3. Большинство пользовательских интерфейсов, независимо от платформ и языка, могут получить доступ к пользовательскому интерфейсу только в основном потоке пользовательского интерфейса, и обычно это объясняется тем, что создание потокобезопасного пользовательского интерфейса очень сложно и не стоит усилий, и это повлечет за собой довольно серьезные штрафы за скорость, что нежелательно, поскольку графическая среда пользовательского интерфейса должна быть быстрой иотзывчивый.
Ответ №1:
Да, ваше право: вы не можете изменять представления в другом потоке в целях безопасности (вот почему он называется потоком пользовательского интерфейса). Это не позволяет вам оставлять данные пользовательского интерфейса в несогласованном состоянии, что может привести к сбою вашего приложения и будет очень сложно отлаживать. Таким образом, Android API просто запрещает это (и это хорошая идея). Это распространенный шаблон пользовательского интерфейса, который вы найдете в большинстве API.
Вы можете обновить любое представление с помощью post() или runOnUiThread():
anyView.post(new Runnable() {
public void run() {
// do update here
}
});
Почему этот шаблон?
Синхронизация не бесплатна. Это влияет на производительность. Так что проще сохранять изменения пользовательского интерфейса в том же потоке.
Если бы я мог изменять данные из разных потоков, что могло бы произойти?
Например: поток A
изменяет цвет представления, а поток B
одновременно считывает цвет. Поскольку многопоточность не гарантирует, какая инструкция будет выполнена первой, вы можете получить неожиданные результаты. Раньше цвет был черным ( 0|0|0
), поток A
хочет установить white ( 255|255|255
) и начать с установки красного компонента 255
, поток B
начинает читать и получает весь цвет до того, как поток A
успел закончить и получил цвет red ( 255|0|0
) вместо black .
Это простой пример, который повлияет на визуальный эффект, но если это произойдет для некоторых действительно важных данных, ваше приложение ужасно рухнет, и такая ошибка настолько неприятна и сложна для отладки. О многопоточности можно многое узнать, и, возможно, этот учебник по Java станет хорошей отправной точкой…
Ответ №2:
Приложение Android использует однопоточную модель, и этот поток отвечает за отправку различных событий элементам пользовательского интерфейса. Эта однопоточная модель имеет два правила :
- Не блокируйте поток пользовательского интерфейса
- Не получить доступ к инструментарию пользовательского интерфейса Android извне потока пользовательского интерфейса
Если вы создаете поток, который использует View
вне UI thread
, то это нарушает вторые правила.
Ответ №3:
Безопасность — это не единственный поток пользовательского интерфейса, который может получить доступ к представлениям. Основная причина в том, что код, стоящий за представлениями, вероятно, не является потокобезопасным. Это означает, что нет никаких гарантий, что данные не будут повреждены, если у вас есть несколько потоков, считывающих и записывающих в общие переменные.
Ознакомьтесь с этой замечательной статьей в Википедии о безопасности потоков.