screen orientation sensor что это
Ориентация
Вступление
Рассмотрим следующий случай. Предположим, у нас в приложении имеется одно текстовое поле и шесть кнопок. Вроде всё нормально.
Но стоит нам повернуть устройство на 90 градусов, как сразу обнаруживаются проблемы. Пятая кнопка видна частично, а шестая вообще оказалась за пределами видимости. Непорядок!
Чтобы избежать такой проблемы, необходимо как-то по другому скомпоновать кнопки. Например, расположить их не подряд друг за другом, а разбить на пары. Воспользуемся контейнером TableLayout. С его помощью мы можем разбить кнопки на две колонки и поместить их в три ряда.
Для этой операции нам понадобится сделать несколько важных шагов. Сначала нужно создать новую подпапку в папке res. Выделяем папку res, вызываем из него контекстное меню и последовательно выбираем команды New | Android resource directory. В диалоговом окне из выпадающего списка Resource type: выбираем layout. В списке Available qualifiers: находим элемент Orientation и переносим его в правую часть Chosen qualifiers: с помощью кнопки с двумя стрелками. По умолчанию у вас появится имя папки layout-port в первой строке Directory Name:. Но нам нужен альбомный вариант, поэтому в выпадающем списке Screen orientation выбираем Landscape. Теперь название папки будет layout-land.
Можно обойтись без помощи мастера, создав папку сразу через меню New | Directory. Этот способ годится для опытных разработчиков, которые знают, как следует назвать папку. Важно запомнить, что имя даётся не произвольно, а именно в таком виде layout-land. По суффиксу -land система понимает, что речь идёт о новом режиме. Теперь нам осталось создать в созданной папке новый XML-файл activity_main.xml. Вызываем контекстное меню у папки layout-land и выбираем команды New | Layout Resource File. В диалоговом окне присваиваем имя activity_main.xml, которое должно совпадать с именем существующего файла. Во втором поле вводим LinearLayout, по мере ввода появится подсказка, облегчающая выбор.
Откроем созданный файл и модифицируем его следующим образом.
Запускаем приложение и проверяем. Отлично, теперь видны все кнопки. Поздравляю, вы гений!
Когда вы создаёте альтернативную разметку, то не забывайте включать все компоненты, к которым будете обращаться программно, иначе получите ошибку. Допустим, вы забыли добавить шестую кнопку. В портретном режиме программа будет работать, а когда пользователь перевернёт экран, то активность будет инициализировать все компоненты для работы, а кнопки-то и нет. Крах приложения и минусы в отзывах.
Узнать ориентацию программно
Чтобы из кода узнать текущую ориентацию, можно создать следующую функцию:
Вызовите данную функцию из нужного места, например, при щелчке кнопки и узнайте текущую ориентацию. В примере использовались две распространённые системные константы для ориентации. Есть ещё константа ORIENTATION_SQUARE (квадратный экран). Но я таких телефонов не встречал.
Сейчас этот код считается устаревшим и для вычисления размера экрана используются другие методы (описано в примере Экран).
Кручу-верчу, запутать хочу!
Хорошо, мы можем определить текущую ориентацию, но в какую сторону повернули устройство? Ведь его можно повернуть влево, вправо или вообще вверх тормашками. Напишем другую функцию:
Установить ориентацию программно и через манифест
Если вы большой оригинал и хотите запустить приложение в стиле «вид сбоку», то можете сделать это программно. Разместите код в методе onCreate():
Учтите, что в этом случае котам не очень удобно будет пользоваться вашим приложением.
Вы можете запретить приложению менять ориентацию, если добавите нужный код в onCreate().
Но указанный способ не совсем желателен. Лучше установить нужную ориентацию через манифест, прописав в элементе параметр android:screenOrientation:
Кстати, существует ещё один вариант, когда устройство полагается на показания сенсора и некоторые другие:
В Android 4.3 (API 18) появились новые значения (оставлю пока без перевода):
После появления Android 5.0 зашёл на страницу документации и пришёл в ужас. Там появились новые значения.
Запрет на создание новой активности
На примере программной установки ориентации можно увидеть интересный эффект, о котором нужно помнить. Предположим у нас есть кнопка, позволяющая менять ориентацию. Заодно будем менять текст на кнопке, чтобы операция соответствовала надписи.
Теперь посмотрите, что у нас получилось. Запустите проект и нажмите на кнопку. Ориентация экрана поменялась, однако текст на кнопке остался прежним, хотя по нашей задумке он должен измениться.
Нажмём на кнопку ещё раз. Надпись изменится, но ориентация не сменится. И только повторный щелчок повернёт экран в обратную сторону.
По умолчанию, при смене ориентации Android уничтожает и пересоздаёт активность из кода, что подразумевает повторный вызов метода onCreate(). Поэтому при повороте активность устанавливала текст, определенный в onCreate(). В большинстве случаев это не мешает программе. Но если приложение воспроизводит видео, то при смене ориентации вызов onCreate() может привести к повторному началу воспроизведения (если так написан пример).
Чтобы активность не пересоздавалась, добавьте в манифест строчку для нужной активности:
При изменении ориентации система вызовет метод onConfigurationChanged(Configuration) и мы можем отловить поворот экрана:
В документации говорится, что данный способ следует избегать.
Исчезающий текст
Как уже говорилось, при смене ориентации активность пересоздаётся. При этом можно наблюдать интересный эффект с пропадающим текстом. Чтобы увидеть эффект, создадим два текстовых поля. Одному из них присвоим идентификатор, а другое поле оставим без него.
Запустите приложение, введите любой текст в обоих полях и смените ориентацию. Вы увидите, что у поля с идентификатором текст при повороте сохранится, а у поля без идентификатора текст исчезнет. Учитывайте данное обстоятельство.
К вышесказанному могу добавить, что при смене ориентации у поля с идентификатором вызывается метод onTextChanged():
Проверка на существование
Если вы используете две разные разметки, то возможна ситуация, когда в альбомной ориентации используется кнопка, которой нет в портретной ориентации. Это можете привести к ошибке в коде, поэтому нужно проверить существование кнопки:
На практике такое встречается редко, но помните на всякий случай.
Запоминаем значения переменных
С поворотом экрана возникает одна очень неприятная проблема. Вдумайтесь в значение слов, что при повороте экрана активность создаётся заново. Чтобы было понятно, нужно вернуться к проекту, в котором мы считали ворон. Если вы его удалили, то придётся пройти урок заново и восстановить его.
А что собственно произошло? Я же вас предупреждал, что активность при повороте создаётся заново. А значит переменная mCount снова принимает значение 0, т.е сбрасывается в начальное значение.
Создадим ключ с именем KEY_COUNT. В Android Studio c версии 1.5 появились живые шаблоны, позволяющие быстро создать ключ. Введите до метода onCreate() строчными буквами слово key, во время набора появится подсказка. Нажимаем Enter и получаем заготовку. После символа подчёркивания вводим название ключа. В результате получим ключ следующего вида.
Далее создаём метод onSaveInstanceState() после метода onCreate(). Во время набора имени метода подсказка покажет, что имеется два метода. Выбирайте метод с одним параметров (обычно он идёт вторым). Записываем в ключа значение счётчика.
А в методе onCreate() делаем небольшую проверку.
У метода в параметре содержится объект Bundle. Только здесь он назван savedInstanceState вместо outState, но пусть вас это не вводит заблуждение. Имена вы можете придумывать сами. Главное, что объект содержит сохранённое значение переменной при повороте. При первом запуске приложения объект не существует (null), а потом мы его создали своим кодом. Для этого и нужна проверка. Обратите внимание, что здесь мы не прибавляем единицу к счётчику, как у кнопки. Если скопировать код у кнопки, то получится, что счётчик будет увеличиваться самостоятельно при поворотах без нажатия на кнопку. Прикольно, конечно, но может ввести в заблуждение пользователя. Хотя, если вы пишите приложение «Я твой дом труба шатал», то такой способ может пригодиться для подсчёта, сколько раз вы вертели телефон, чтобы разрушить чей-то дом.
Обращаю ваше внимание, что данный способ используется для сохранения промежуточных результатов во время действия программы. В следующих уроках вы узнаете, как можно сохранять результат между запусками приложения.
Ориентация у фрагментов
Позже вы узнаете о существовании фрагментов. Может возникнуть такая ситуация, когда вы захотите выводить конкретный фрагмент в нужной ориентации. У фрагментов есть собственный жизненный цикл, и вы можете реализовать свой код в методах фрагмента:
Я с таким случаем не встречался, но оставлю как памятку.
Жизненный цикл при повороте
При повороте активность проходит через цепочку различных состояний. Порядок следующий.
Разница между SCREEN_ORIENTATION_USER и SCREEN_ORIENTATION_SENSOR
При разработке приложения для Android я нашел два атрибута ActivityInfo для настройки ориентации экрана.
Атрибуты, имеющие USER, следующие:
Атрибуты, имеющие SENSOR, следующие:
В чем разница между SCREEN_ORIENTATION_USER и SCREEN_ORIENTATION_SENSOR?
Атрибуты, имеющие USER, следующие.
Используйте текущую предпочтительную ориентацию телефона. Соответствует SCREEN_ORIENTATION_USER.
Желательно иметь экран в альбомной ориентации, но если пользователь включил поворот на основе датчика, мы можем использовать датчик для изменения направления, в котором находится экран. Соответствует SCREEN_ORIENTATION_USER_LANDSCAPE.
Хотелось бы иметь экран в портретной ориентации, но если пользователь включил вращение на основе датчика, мы можем использовать датчик для изменения направления, в котором находится экран. Соответствует SCREEN_ORIENTATION_USER_PORTRAIT.
Атрибуты, имеющие SENSOR, следующие.
Ориентация определяется датчиком физической ориентации: дисплей вращается в зависимости от того, как пользователь перемещает устройство. Игнорирует настройку пользователя, чтобы отключить вращение на основе датчика. Соответствует SCREEN_ORIENTATION_SENSOR.
Хотел бы иметь экран в альбомной ориентации, но может использовать датчик для изменения направления в сторону экрана. Соответствует SCREEN_ORIENTATION_SENSOR_LANDSCAPE.
Хотел бы иметь экран в портретной ориентации, но может использовать датчик для изменения направления, с которым смотрит экран. Соответствует SCREEN_ORIENTATION_SENSOR_PORTRAIT.
Android screen orientation to sensor
I want to force the screen orientation to landscape on button click by setting
It works fine. Now I want the application to follow the sensor so that orientation is brought back to portrait when tilted back to portrait. I know this is possible by setting setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); but don’t know where to set it. If the orientation is forced to landscape, orientation will remain in landscape no matter you tilt in any direction. Can anyone specify how to reset the orientation flag?
3 Answers 3
Current YouTube app does what you are asking for.
I’ve dealt with same kind of problem in my application for video playback.
If user forces orientation to landscape when he/she was in portrait, initialise OrientationEventListener which notifies you on device orientation from SensorManager which ranges from 0 to 360.
Here is the demo code:
This worked similar to YouTube functionality, hope this helps.
I think here you should use setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
It depends on when you want the sensor to detect rotation again.
Personally in an app I’m developping I have one specific activity where I need to be in portrait mode, so I use setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); in the onResume() of this activity and setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); in onPause() and it works just fine, when I enter the activity it sets to portrait if it’s not and doesn’t allow to change and on exitting the sensor works again.
Where are you trying to enable and disable the sensor?
Полный список
— читаем данные с сенсоров
В этом уроке я попробую изложить то, что я понял из всего мною прочитанного по сенсорам. Рассмотрим, как можно получить данные от сенсоров и как эти данные можно использовать.
Android поддерживает несколько типов сенсоров. В данный момент хелп сообщает, что таких типов 13. Мы в этом уроке рассмотрим сенсоры света, ускорения, гравитации и магнитного поля.
Список сенсоров. Сенсор света.
Первое приложение будет выводить нам список доступных сенсоров и данные с сенсора света.
Project name: P1371_Sensors
Build Target: Android 2.3.3
Application name: Sensors
Package name: ru.startandroid.develop.p1371sensors
Create Activity: MainActivity
В strings.xml добавим строки:
Кнопки для получения списка сенсоров и данных по свету, и TextView для отображения данных.
В onCreate получаем SensorManager. У него запрашиваем полный список сенсоров, используя метод getSensorList и передавая туда тип сенсора TYPE_ALL.
Чтобы получить конкретный сенсор (Sensor), вызываем метод getDefaultSensor. Передаем тип TYPE_LIGHT и получаем сенсор света. Тут аккуратнее, т.к. если такого сенсора в девайсе нет – то метод вернет null.
В onClickSensList мы отписываем слушателя от сенсора. Об этом чуть позднее.
Далее берем список сенсоров и выводим по ним инфу на экран:
getName – имя
getType – тип
getVendor – создатель
getVersion – версия
getMaximumRange – максимальное значение, которое может вернуть сенсор
getResolution – насколько я понял, это минимальный шаг, с которым может изменяться значение
Правда хелп пишет, что система может проигнорить это значение и выдавать данные как ей удобно. А начиная с API Level 9 можно вместо константы скорости передавать свое значение в микросекундах. Не перепутайте с миллисекундами.
В onPause мы отписываем своего слушателя от сенсора света. Тут, как обычно, рекомендуется отписываться как только данные вам не нужны, чтобы не расходовать зря батарею.
listenerLight – слушатель, реализует интерфейс SensorEventListener. У него два метода:
onAccuracyChanged – вызывается, когда меняется точность данных сенсора и в начале получения данных. Дает нам объект-сенсор и уровень точности:
SENSOR_STATUS_ACCURACY_HIGH – максимально возможная точность
SENSOR_STATUS_ACCURACY_MEDIUM – средняя точность, калибровка могла бы улучшить результат
SENSOR_STATUS_ACCURACY_LOW – низкая точность, необходима калибровка
SENSOR_STATUS_UNRELIABLE – данные сенсора совсем ни о чем. Либо нужна калибровка, либо невозможно чтение данных.
onSensorChanged – здесь то мы и получаем данные от сенсора в объекте SensorEvent.
Все сохраняем и запускаем приложение. Жмем List и получаем список.
У меня он выглядит вот так:
На скрине видно, что в устройстве есть несколько сенсоров одного типа. Если вместо TYPE_ALL передать в метод getSensorList какой-либо конкретный типа сенсора, то получим список сенсоров только этого типа.
Теперь нажмем Light. Приложение покажет текущее значение освещенности. Попробуйте менять яркость освещения рядом с девайсом, должно меняться значение.
У меня в полутемной комнате показывает 0. Если взять фонарик и издалека начать подносить к датчику света покажет последовательно: 10, 100, 1000, 10000 и в конце 30000. При этом, на скрине со списком сенсоров видно, что максимум значения = 3000, а шаг (если я правильно понял параметр resolution) = 1. Почему такое несоответствие инфы с реальностью – я не знаю.
Ускорение
Далее рассмотрим сенсоры движения. Для этого нам надо будет понять, что в нашем трехмерном пространстве у устройства есть три оси. В хелпе гугла есть такая картинка.
Т.е. если держать устройство перед собой, то ось X проходит слева направо, ось Y проходит снизу вверх, ось Z проходит сквозь устройство в вашем направлении. Сенсор ускорения вернет нам массив из трех значений, каждое из которых соответствует определенной оси.
Project name: P1372_Acceleration
Build Target: Android 2.3.3
Application name: Acceleration
Package name: ru.startandroid.develop.p1372acceleration
Create Activity: MainActivity
В onCreate мы получаем три сенсора:
TYPE_ACCELEROMETER – ускорение, включая гравитацию (ту самую, которая 9.8, из физики)
В onResume регистрируем один слушатель listener на все три сенсора. И запускаем таймер, который будет каждые 400 мсек отображать данные в TextView.
В onPause отписываем слушателя от всех сенсоров, вызывая метод unregisterListener, но не указывая конкретный сенсор. И отключаем таймер.
Метод format просто отформатирует float значения до одного знака после запятой.
showInfo выведет в TextView данные. Данные у нас будут в пяти массивах.
В слушателе listener в методе onSensorChanged мы определяем тип сенсора и пишем данные в соответствующие массивы:
valuesAccel – данные с сенсора ускорения (включая гравитацию)
valuesAccelMotion и valuesAccelGravity – данные из valuesAccel, разделенные с помощью вычислительного фильтра на чистое ускорение (без гравитации) и гравитацию.
valuesLinAccel – данные с сенсора ускорения без гравитации
valuesGravity – данные с сенсора гравитации
Т.е. мы получаем данные по ускорению (valuesAccel) с сенсора TYPE_ACCELEROMETER и потом вычислительным фильтром сами разбиваем на чистое ускорение и гравитацию. Но можно так не заморачиваться, а использовать сенсоры TYPE_LINEAR_ACCELERATION и TYPE_GRAVITY, которые должны дать нам примерно тот же результат.
Кстати, обратите внимание, как я считываю данные в свой массив. Я читаю значения и пишу их себе. Почему просто не выполнить присваивание типа: valuesAccel = event.values? Если так сделать, то могут периодически проскакивать кривые данные, если вы несколько сенсоров читаете. Там, похоже, используется пул объектов, чтобы сборщик мусора не грузить таким диким кол-вом новых объектов на единицу времени. Соответственно, если вы возьмете объект по ссылке, то пока он дойдет у вас до обработки, система может снова взять его в оборот и записать в него уже новые значения, причем еще и от другого сенсора. Так что лучше читать значения, а не ссылку брать.
Запустим приложение. И положим девайс на стол экраном вверх.
Еще раз обсудим, что вывелось на экран
Accelerometer: данные по ускорению + гравитация. Видим, что третья ось (Z), которая в лежачем положении проходит вертикально вверх, показывает ускорение примерно равное гравитации. Т.е. даже в состоянии покоя сенсор показывает не чистое ускорение а еще и гравитацию, что не всегда нужно.
Мы использовали фильтр, чтобы отделить ускорение от гравитации.
Accel motion: чистое ускорение, вычисленное из ускорения с гравитацией. Здесь все нули, т.к. устройство лежит и не двигается.
Accel gravity: гравитация, вычисленная из ускорения с гравитацией. Здесь первые две оси = нулю, т.к. они проходят паралелльно земле и по этим осям гравитации нет. Зато она есть по третьей оси, которая проходит вертикально. Проще говоря планета не тянет нас влево-вправо-вперед-назад, она тянет нас вниз. Поэтому показывать ускорение в 9.8 будет та ось, которая находится вертикально к земле.
Lin accel: данные с сенсора чистого ускорения (без гравитации). Тут все нули, т.к. устройство в состоянии покоя. Эти значения примерно должны совпадать с теми, что мы посчитали в Accel motion.
Gravity: данные с сенсора гравитации. Третья ось показывает, что она находится вертикально, т.к. гравитация по ней близка к максимуму. Эти значения должны совпадать с теми, что мы посчитали в Accel gravity.
Вы можете подвигать устройство в таком положении с ускорением в разные стороны и понаблюдать, как меняются значения осей. Правда, не очень наглядно получается. Если строить по этим значениям график, будет, конечно, лучше видно их изменения во времени.
Теперь я возьму устройство в руки и подниму перед собой так, чтобы оно было на уровне глаз, а экран смотрел на меня. Т.е. так же, как выше в тексте, на картинке c осями.
Смотрим, как изменились данные.
Accelerometer: четко видно, что теперь вторая ось (Y) расположена почти вертикально, по ней идет гравитация 9.8. А оси X и Z близки к нулю. Они не равны точно нулю, т.к. я держу устройство не идеально ровно и небольшие перекосы дают гравитацию и на эти оси.
Т.е. вывод можно сделать следующий. Чем ближе значение оси к 9.8, тем вертикальнее ее положение в пространстве. А чем ближе к нулю, тем горизонтальнее.
Accel motion и Lin accel показывают нам чистое ускорение. Оно близко к нулю, т.к. я стараюсь не дергать устройство.
Accel gravity и Gravity показывают, что по второй оси имеем почти полную гравитацию, а значит ось расположена вертикально.
Попробуйте понаклонять устройство в разные стороны и наблюдайте как меняется гравитация. При переходе оси от горизонтального положения к вертикальному значение сенсора по этой оси будет меняться от 0 до 9.8.
Ориентация
Теперь попробуем использовать данные сенсора ускорения и добавим к ним данные сенсора магнитного поля. Эти два набора данных при определенных манипуляциях дадут нам углы наклона устройства. Угла будет три, по одному для каждой оси.
Project name: P1373_Orientation
Build Target: Android 2.3.3
Application name: Orientation
Package name: ru.startandroid.develop.p1373orientation
Create Activity: MainActivity
В onCreate мы получаем сенсоры ускорения (TYPE_ACCELEROMETER) и магнитного поля (TYPE_MAGNETIC_FIELD).
В onResume вешаем слушателя и запускаем таймер, который каждые 400 мсек будет определять ориентацию девайса в пространстве и выводить эту инфу на экран. В переменную rotation получаем значение текущей ориентации экрана. Это нам понадобиться для корректного определения ориентации девайса.
В onPause отключаем слушателя и таймер.
Метод format просто отформатирует float значения до одного знака после запятой.
showInfo покажет данные массивов в TextView. Но сначала эти данные надо вычислить. Этим займутся следующие два метода.
Метод getDeviceOrientation определяет текущую ориентацию девайса в пространстве без учета поворота экрана. Для этого мы сначала вызваем метод getRotationMatrix, который берет данные ускорения и магнитного поля и формирует из них матрицу данных в переменную r. Далее метод getOrientation из этой матрицы позволяет получить массив значений (в радианах) поворота трех осей. Остается перевести радианы в градусы методом toDegrees и у нас есть готовый массив с углами наклона девайса.
Метод getActualDeviceOrientation аналогичен методу getDeviceOrientation, но он позволяет учесть ориентацию экрана. Для этого мы дополнительно вызываем метод remapCoordinateSystem, который пересчитает нам матрицу. С помощью переменных x_axis и y_axis мы передаем в этот метод данные о том, как оси поменялись местами при повороте экрана.
Слушатель listener получает данные ускорения и магнитного поля и пишет их в массивы valuesAccel и valuesMagnet.
Запускаем приложение. Кладем устройство на ровную поверхность.
Orientation: данные по ориентации в пространстве без учета ориентации экрана устройства.
Orientation 2: данные по ориентации в пространстве с учетом ориентации экрана устройства. Они равны данным Orientation если экран устройства находится в нормальной ориентации.
Здесь, в отличие от ускорения, оси немного в другом порядке показаны. Первая цифра – это угол по оси Z. В горизонтальном положении устройства, это число показывает градус отклонения от севера. Т.е. это компас. Поверните устройство, сохраняя горизонтально положение, так, чтобы первая цифра стала близка к нулю. Теперь ваш девайс должен смотреть строго на север.
Третья цифра – угол по оси Y. Тут аналогично оси X. Если положить устройство на стол, и начать поднимать его правую сторону, оставляя левую на столе (как будто переворачиваем страницу), будет меняться третья цифра. Она покажет угол наклона по оси Y. Попробуйте также поднимать левую, оставляя правую на столе.
Тем самым мы получили полную картину положения девайса в пространстве.
Попробуйте поменять ориентацию экрана и заблокировать ее в настройках. И снова потестируйте наклоны. Вы увидите, что данные Orientation выводятся относительно стандартной ориентации экрана, а Orientation2 – относительно текущей ориентации экрана.
Прочее
Еще немного инфы по теме сенсоров.
Сенсоры бывают реальные (hardware) и виртуальные (virtual). Реальные – это датчики, которые дают нам значения. А виртуальные используют значения реальных и по ним вычисляют свои значения. В рассмотренных нами примерах мы использовали реальный сенсор ускорения (TYPE_ACCELEROMETER) и из него сами посчитали чистое ускорение и гравитацию. Используемые нами там же сенсоры чистого ускорения (TYPE_LINEAR_ACCELERATION) и гравитации (TYPE_GRAVITY) являются виртуальными и так же, как и мы вычисляют свой результат. Только, я думаю что механизм подсчета там отличен от нашего и позволяет получить более реальные результаты.
Сенсор-гироскоп (TYPE_GYROSCOPE) показывает скорость вращения по осям в радиан/сек.
У сенсора есть еще такая характеристика как power – потребляемая мощность (mA). Чем она ниже, тем, разумеется, лучше для батареи.
Если ваше приложение обязательно использует сенсор и не будет без него работать, вы можете указать это в манифесте с помощью тега uses-feature. В этом случае Google Play не должен дать поставить приложение на устройство, которое не имеет указанного сенсора.
Пример для сенсора ускорения.
Значения других сенсоров можно найти в хелпе в секции Sensors.
На следующем уроке:
— получаем данные о местоположении
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме