Почему поток, который не является потоком пользовательского интерфейса, не может получить доступ к представлению? - PullRequest
2 голосов
/ 09 октября 2011

Я знаю, что ни один поток не может получить доступ к текущему представлению, если это не поток пользовательского интерфейса. Мне интересно почему? Почему важно, какая нить меняет представление? Это причина безопасности? Это обходной путь, который я использую:

        public void doLayout()
        {
            Runnable run = new Runnable()
            {
                public void run()
                {
                    ViewerActivity.setContentView(R.layout.main);
                }
            };

            handler.post(run);
        }

        private Handler handler;'

Это довольно болезненно делать каждый раз, когда я хочу изменить макет. Есть ли другая работа вокруг? Я знаю об асинхронной задаче и никогда не находил хороший способ ее использовать, это лучше, чем то, что я делаю? Все соответствующие ответы оценены!

Ответы [ 3 ]

13 голосов
/ 09 октября 2011

Да, ваше право: Вы не можете изменять представления в другом потоке в целях безопасности (поэтому он называется потоком пользовательского интерфейса).Он не позволяет оставлять данные пользовательского интерфейса в несогласованном состоянии, что может привести к сбою приложения и его будет очень сложно отладить.Так что android API просто запрещает это (и это хорошая идея).Это обычный шаблон пользовательского интерфейса, который вы найдете в большинстве API.

Вы можете обновить любое представление с помощью post () или runOnUiThread () :

anyView.post(new Runnable() {
    public void run() {
        // do update here
    }
});

Почему этот шаблон?
Синхронизация не бесплатна.Это влияет на производительность.Таким образом, проще сохранить изменения в пользовательском интерфейсе в одном потоке.

Если бы я мог изменять данные из разных потоков, что могло бы произойти?
Например: поток A изменяетцвет вида и нити B читает цвет в то же время.Поскольку многопоточность не гарантирует, какая инструкция будет выполнена первой, вы можете получить неожиданные результаты.Цвет черный (0|0|0) раньше, поток A хочет установить белый (255|255|255) и начать с установки красного компонента на 255, поток B начинает читать и получает весь цвет перед потокомA имел возможность закончить и получил красный цвет (255|0|0) вместо черного.

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

1 голос
/ 09 октября 2011

Безопасность - не единственный поток пользовательского интерфейса, это единственный поток, который может получить доступ к представлениям. Основная причина в том, что код за представлениями, вероятно, не является потокобезопасным. Это означает, что нет никаких гарантий, что данные не будут повреждены, если у вас есть несколько потоков, читающих и записывающих в общие переменные.

Прочтите эту замечательную статью в Википедии о безопасности потоков.

1 голос
/ 09 октября 2011

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

  1. Не блокировать поток пользовательского интерфейса
  2. Не получать доступ к инструментарию пользовательского интерфейса Android извне потока пользовательского интерфейса

Если вы создаете поток, который использует View вне UI thread, тогда он нарушает вторые правила.

...