- Русские Блоги
- Android WindowManager
- Android WindowManager
- Основной метод
- Главный орган
- WindowManager LayoutParams связанные свойства
- Код дела
- Анализ связанных элементов управления
- Как не выйти в Window при работе с Window?
- Официальная документация от Google
- onResume()
- Activity
- Window
- DecorView
- ViewRootlmpI
- WindowManager
- Схема взаимодействий
- Почему фрагмент
- DialogFragment
- Хаки с Window
- Что такое WindowManager в android?
Русские Блоги
Android WindowManager
Android WindowManager
Эта статья была написана Luzhuo, пожалуйста, сохраните эту информацию для перепоста.
Оригинал: https://blog.csdn.net/Rozol/article/details/86658357
WindowManager — это оконный объект, который может обеспечить эффект плавающего вида в других приложениях.
Основной метод
Получить объект формы
Получить размер объекта формы
Добавить / удалить / обновить вид
Главный орган
Нужно добавить разрешение на всплывающие плавающие окна в макете
Android6.0 + требует разрешения пользователя для открытия плавающих окон
После права открывать плавающее окно, после того, как программа открывает плавающее окно, панель уведомлений также будет содержать информацию уведомления.
Типы разрешений, которые Android8.0 должен обрабатывать
WindowManager LayoutParams связанные свойства
Параметры флагов:
Остальное — это тип, и некоторые часто используемые настройки, тут не о чем говорить.
Тип используется в api26 +, если он не на системном уровне TYPE_APPLICATION_OVERLAY Для этого типа официальная документация пометила это для типов, которые не являются системными:
Однако в более ранних версиях TYPE_APPLICATION_OVERLAY Не сработает, поэтому используйте код в кейсе для борьбы с ним.
Код дела
Android6.0 открывает разрешение вручную, я написал это в Activity, я не буду вставлять его сюда, просто вставьте код службы.
Эффект изображения:
Анализ связанных элементов управления
Вы можете часто использовать Toast или Dialog, эти элементы управления могут отображаться на рабочем столе, потому что эти элементы управления также используют WindowManager.
Источник
Как не выйти в Window при работе с Window?
Многие разработчики разбиваются о жизненные циклы onResume, onStart, onCreate, которые связаны с отображением UI внутри приложения, будь то Activity или Fragment. Некоторые методы работы со стремительно развивающимся андроидом приходится искать интуитивно, потому что официальная документация не всегда дает полной картины, а иногда даже вводит в заблуждение. Стоит разобраться, где заканчиваются знания и начинается интуиция.
Я Дмитрий Манько, андроид-разработчик в компании Ситимобил, попробую объяснить, что такое onResume() и почему определение от Google не совсем корректное. Разберу иерархию внутри Activity, покажу когда происходит взаимодействие и какие события для этого нужны. А ещё объясню, почему Fragment дешевле и проще Activity.
Сразу начнем с практики. Давайте рассмотрим кейс:
Есть MainActivity, который наследуется от обычного AppCompatActivity. В onCreate мы устанавливаем activity_main, переопределяем и морозим onResume.
В качестве верстки для activity_main устанавливаем ConstraintLayout с текстовой кнопкой.
Используется стандартная MaterialComponents тема и телефон запущен в светлой теме.
Попытаемся выбрать правильный ответ на вопрос: «Что произойдет, если заморозить onResume при первом запуске приложения внутри Activity»?
На кнопку нельзя будет нажать, на экране будет отрисована кнопка.
На кнопку нельзя будет нажать, на экране будет отрисован только черный фон.
Можно будет нажать на кнопку, на экране будет отрисована кнопка.
На кнопку нельзя будет нажать, на экране будет отрисован только белый фон.
Результат ответов с конференции
Этот вопрос демонстрирует, чем руководствуются разработчики, знаниями, опытом или интуицией. Например, участники конференции ответили следующим образом:
Четвертый вариант правильный, поэтому не удивительно, что он набрал больше голосов, но остальные ответы близки к нему по популярности. Вариант, что на кнопку нельзя будет нажать, но она будет отрисована, выбрало практически такое же количество опрошенных. А многие из правильно ответивших, не до конца понимали, почему получается именно так. Поэтому, можно сделать вывод, что правильный ответ они просто угадали. Давайте разберемся, почему окно и кнопка так себя ведут.
Большинство разработчиков ожидают получить результат слева, но ни Action Bar, ни кнопка не отрисуются, и ничего, кроме белого фона, не будет.
Официальная документация от Google
В официальной документации от Google написано:
onResume() — This is an indicator that the activity became active and ready to receive input. It is on top of an activity stack and visible to user.
Т.е. это некий указатель на то, что activity становится активной и готова принимать входящие взаимодействия: ввод, вызовы и т.д. Это находится наверху нашего Activity-стека и видно пользователю. Но на самом деле, если onResume() вызвался, а мы морозим поток, то наши View элементы еще не видны пользователю.
Поэтому давайте разбираться. Для этого нам придется спуститься в так называемые «кишки» Андроида и посмотреть, кто вызвал onResume(), кто вызвал тот метод, который вызвал onResume() и отправиться ещё выше.
onResume()
Чтобы было проще понять, как все это между собой взаимодействует, я опущу некоторые подробности. В первую очередь нас интересует, как вызывается onResume.
r — это ActivityClientRecord, то есть обертка, которая содержит инстанс нашей Activity и дополнительную информацию о её состоянии. Она вызывает метод performResumeActivity. Он дает ответ, что тот onResume, который мы заморозили, был вызван.
Идем выше, чтобы понять, кто вызывает метод performResumeActivity
Кто вызвал performResumeActivity()
С помощью переменной присваивается ActivityClientRecord и в нашем путешествии появляются сущности:
Их мы разберем позднее, а сейчас нас интересует код в конце вызова метода activity makeVisible()
Перейдем к погружению в метод makeVisible():
Отметим, что имплементация находится в таком классе как Activity.
Код метода makeVisible() выглядит следующим образом:
Мы получаем WindowManager, добавляем к нему mDecor, кладем атрибуты, и делаем mDecor видимой.
Посмотрим, что происходит внутри метода addView у WindowManager.
У нас существует имплементация WindowManager — WindowManagerImpl. В WindowManagerImpl я не стал описывать происходящее, потому что он делегирует вызов в WindowManagerGlobal. Как видно, это применение того же метода, но уже у самого WindowManagerGlobal.
Взглянем подробнее на WindowManagerGlobal:
В нем происходит инициализация ViewRootImpl и добавляются наши атрибуты в массив Views, массив Roots и массив Params. Самое важное — это конечное действие, которое обернуто в try/catch. Здесь у нас устанавливается метод setView нашей ViewRootImpl.
Именно в этот последний промежуток у нас root.setView() устанавливает наши View, начиная от DecorView и это позволяет проинициализировать все необходимое для старта отображения, и запустить тот самый performTraversals.
Возможно, вы знаете про этот метод, но на всякий случай напомню.
PerformTraversals прогоняет жизненный цикл наших Views. Он измеряет и рисует, начиная с корневой и заканчивая дочерними.
Почему так сложно?
Нельзя ли сделать проще?
Чтобы разобраться, давайте попытаемся дать свое определение:
onResume() — метод жизненного цикла Activity, который уведомляет, что необходимый контент был добавлен в DecorView, но будет отображен только тогда, когда ViewRootlmpI установит эту view и выполнит обход вызовов методов View для отрисовки.
Звучит сложно, поэтому и говорят, что сейчас это будет видно пользователю. Но в формулировке от компании Google я бы поправил, что не «видно пользователю», а «вот-вот будет видно», так будет корректней.
Должен признать, что к моменту выхода этой статьи, Google убрала эти двусмысленные строчки, теперь часть описания метода onResume() выглядит так:
onResume() — This is usually a hint for your activity to start interacting with the user, which is a good indicator that the activity became active and ready to receive input.
Activity
Activity — это контроллер, который обрабатывает входящие события. Но это вовсе не сущность, которая отвечает за View.
Она реагирует на какие-то события, добавляет и отображает View, а также взаимодействует через обратные методы и содержит внутри себя Window.
Так можно понять примерную иерархию: внутри Activity есть Window.
Window
Window — это обертка над DecorView.
Ее задача — передать DecorView ViewRootlmpI для отрисовки и уведомить Activity о том, что произошло событие.
DecorView
DecorView — это корневая View.
Ее можно увидеть в Layout Inspector, но давайте разберемся, что это такое.
Наш контент находится здесь. Также у нас есть navigationBar и statusBar. По сути, DecorView это обычная View, точнее наследник FlameLayout. Она находится внутри Window.
ViewRootlmpI
ViewRootlmpI — это связующий класс между Window Manager Service и DecorView. Все взаимодействия, измерения, расположение и отрисовка View проходят через него
Несмотря на название, он не является частью View-иерархии, не является View в привычном понимании Андроида. Это связующее звено, которое получает события от сервиса и передает обратно View, View Activity и т.д., и мы получаем сообщение о том, что что-то произошло.
WindowManager
WindowManager — это системная служба, управляющая отображением списка Window.
Она отвечает за анимации при закрытии приложения, вращение и другие операции с окнами.
Схема взаимодействий
Найденная на просторах интернета схема мне полностью подходила, и я решил ее не переделывать.
В схеме видно, что есть Activity или Dialog, внутри него PhoneWindow — это единственная имплементация от Window. Внутри него DecorView и View. Есть WindowManager, внутри него ViewRootlmpI и WindowManagerService — это сервис, который управляет окнами.
Почему Activity и Dialog здесь на одном уровне расскажу дальше.
Взаимодействие происходит, когда:
Мы сообщаем из Активити что мы установили в иерархию View что-то
Мы сообщаем это Window
Window передает это DecorView
DecorView передается в ViewRootlmpI
WindowManager — WindowManager service
Обратно происходят почти тоже самое, но к примеру при физическом касании экрана Manager ответственный за входящие взаимодействия сообщает о событии ViewRootlmpI, ViewRootlmpI сообщает DecorView и т.д.
Есть разные вариации этой схемы, но они отображают одно и то же.
Почему фрагмент
Я много раз слышал, что фрагмент дешевле и проще, чем Activity, но не слышал конкретных причин, кроме идеологических
Причина в том, что для Activity нужно создать DecorView, Window и т.д., то есть пройти первый цикл отрисовки и поставить параметры. Для фрагмента нужно намного меньше, достаточно добавить фрагмент в уже существующую иерархию, которую создала Activity.
Я обещал рассказать, почему на схеме взаимодействия были показаны диалоги.
DialogFragment
На самом деле DialogFragment создает свой DecorView, но у него совершенно другой Window, и все необходимые компоненты, для того чтобы находиться поверх окна, который содержит Activity. Этот DecorView не встроен в иерархию Activity, хотя является фрагментом. Такой способ показа диалога независим от нашей Activity, и от этого возникают эффекты тени и прочее.
Хаки с Window
Все эти знания позволяют нам, например, с помощью WindowManager делать отображение над любыми другими приложениями и меню, так у драйверского приложения есть плавающая иконка (это не иконка запуска)
С помощью сервиса установки разных форматов WindowManager, мы можем сделать плавающее приложение, которое будет открывать, закрывать и выполнять другие действия. Так работает, например, запись экрана.
Главное учитывать ограничения, которые есть на платформах, и то, что Window необходимо создавать из сервиса, чтобы он не был привязан ни к Activity, ни к фрагменту, тогда окно будет постоянно отображено.
Источник
Что такое WindowManager в android?
Я попробовал поиграть в него, и нет прямого и / или четкого ответа.
Непонятно определение веб – сайта разработчика :
Интерфейс, который приложения используют для работы с диспетчером окон. Используйте Context.getSystemService(Context.WINDOW_SERVICE) чтобы получить один из них.
Может ли кто-то с простым английским языком объяснить, что это такое?
И как я могу использовать его для создания плавающего объекта, который остается в нескольких активах, хотя я перешел от одного к другому?
Android WindowManager – это системная служба, которая отвечает за управление z-упорядоченным списком окон, какие окна видны и как они выложены на экране. Помимо прочего, он автоматически выполняет переходы окон и анимацию при открытии или закрытии приложения или при вращении экрана.
Каждое действие имеет окно, которое используется для отображения его содержимого на экране. Когда вы вызываете setContentView в действии, он прикрепляет это представление к окну по умолчанию для активности. Окно по умолчанию заполняет экран, так что окно активности скрывает любые другие действия – WindowManager отобразит любое окно сверху. Поэтому, как правило, вам не нужно беспокоиться о Windows – вы просто создаете активность, и Android сделает все остальное за вас.
Но вам нужно взаимодействовать с WindowManager, если вы хотите сделать что-то необычное, как создавать плавающие окна, которые не заполняют экран. Если вы хотите создать плавающее окно, которое видимо перед другими приложениями, вы не можете использовать действие, потому что ваша деятельность остановится, когда другое приложение появится на переднем плане, и его окно будет скрыто или уничтожено. Вместо этого вам нужно отобразить окно из фоновой службы. Например:
Для этого вам нужно будет добавить следующие разрешения на ваш AndroidManifest.xml
Диспетчер окон организует экран и обрабатывает то, что должно идти туда, где и как они должны быть слоистыми.
Вот хороший пример с открытым исходным кодом для плавающего объекта. Пример плавающего объекта
Источник