Większość urządzeń z Androidem ma wbudowane czujniki, które mierzą ruch, orientację i różne warunki środowiskowe. Te czujniki mogą dostarczać surowe dane o wysokiej precyzji i dokładności. Są przydatne, jeśli chcesz monitorować trójwymiarowy ruch lub położenie urządzenia albo zmiany w otoczeniu urządzenia. Na przykład gra może śledzić odczyty z czujnika grawitacji urządzenia, aby wnioskować o złożonych gestach i ruchach użytkownika, takich jak przechylenie, potrząśnięcie, obrót czy zamach. Podobnie aplikacja pogodowa może używać czujnika temperatury i czujnika wilgotności urządzenia do obliczania i raportowania punktu rosy, a aplikacja podróżnicza może używać czujnika pola geomagnetycznego i akcelerometru do raportowania kierunku kompasu.
Zapoznaj się z tymi materiałami:
Platforma Android obsługuje 3 główne kategorie czujników:
- Czujniki ruchu
Te czujniki mierzą siły przyspieszenia i siły obrotowe wzdłuż 3 osi. Ta kategoria obejmuje akcelerometry, czujniki grawitacji, żyroskopy i czujniki wektora rotacji.
- Czujniki środowiskowe
Czujniki te mierzą różne parametry środowiskowe, takie jak temperatura i ciśnienie powietrza, oświetlenie i wilgotność. Ta kategoria obejmuje barometry, fotometry i termometry.
- Czujniki położenia
Te czujniki mierzą fizyczne położenie urządzenia. Ta kategoria obejmuje czujniki orientacji i magnetometry.
Za pomocą platformy czujników Androida możesz uzyskać dostęp do czujników dostępnych na urządzeniu i pobrać surowe dane z czujników. Platforma czujników udostępnia kilka klas i interfejsów, które pomagają wykonywać wiele różnych zadań związanych z czujnikami. Za pomocą platformy czujników możesz na przykład:
- Określ, które czujniki są dostępne na urządzeniu.
- Określ możliwości poszczególnych czujników, takie jak maksymalny zasięg, producent, wymagania dotyczące zasilania i rozdzielczość.
- Pobieranie surowych danych z czujników i określanie minimalnej częstotliwości ich pobierania.
- Rejestrowanie i wyrejestrowywanie detektorów zdarzeń czujnika, które monitorują zmiany czujnika.
W tym artykule znajdziesz omówienie czujników dostępnych na platformie Android. Zawiera też wprowadzenie do platformy czujników.
Wprowadzenie do czujników
Platforma czujników Androida umożliwia dostęp do wielu typów czujników. Niektóre z tych czujników są oparte na sprzęcie, a inne na oprogramowaniu. Czujniki sprzętowe to fizyczne komponenty wbudowane w telefon lub tablet. Dane te są uzyskiwane przez bezpośredni pomiar określonych właściwości środowiska, takich jak przyspieszenie, natężenie pola geomagnetycznego czy zmiana kątowa. Czujniki oprogramowania nie są urządzeniami fizycznymi, chociaż naśladują czujniki sprzętowe. Czujniki oprogramowania pobierają dane z co najmniej jednego czujnika sprzętowego i są czasami nazywane czujnikami wirtualnymi lub syntetycznymi. Czujnik przyspieszenia liniowego i czujnik grawitacji to przykłady czujników opartych na oprogramowaniu. W tabeli 1 znajdziesz podsumowanie czujników obsługiwanych przez platformę Android.
Niewiele urządzeń z Androidem ma wszystkie typy czujników. Na przykład większość telefonów i tabletów ma akcelerometr i magnetometr, ale mniej urządzeń ma barometr lub termometr. Urządzenie może też mieć więcej niż 1 czujnik danego typu. Na przykład urządzenie może mieć 2 czujniki grawitacji, z których każdy ma inny zakres.
Tabela 1. Typy czujników obsługiwane przez platformę Android.
Czujnik | Typ | Opis | Częste zastosowania |
---|---|---|---|
TYPE_ACCELEROMETER |
Sprzęt | Mierzy siłę przyspieszenia w m/s2, która jest wywierana na urządzenie na wszystkich 3 osiach fizycznych (x, y i z), w tym siłę grawitacji. | wykrywanie ruchu (potrząsanie, przechylanie itp.); |
TYPE_AMBIENT_TEMPERATURE |
Sprzęt | Mierzy temperaturę otoczenia w stopniach Celsjusza (°C). Patrz uwaga poniżej. | monitorowanie temperatury powietrza, |
TYPE_GRAVITY |
Oprogramowanie lub sprzęt | Mierzy siłę grawitacji w m/s2, która jest wywierana na urządzenie na wszystkich 3 osiach fizycznych (x, y, z). | wykrywanie ruchu (potrząsanie, przechylanie itp.); |
TYPE_GYROSCOPE |
Sprzęt | Mierzy szybkość obrotu urządzenia w rad/s wokół każdej z 3 osi fizycznych (x, y i z). | wykrywanie obrotu (obracanie, skręcanie itp.); |
TYPE_LIGHT |
Sprzęt | Mierzy poziom oświetlenia otoczenia (natężenie oświetlenia) w luksach. | sterowanie jasnością ekranu, |
TYPE_LINEAR_ACCELERATION |
Oprogramowanie lub sprzęt | Mierzy siłę przyspieszenia w m/s2, która jest wywierana na urządzenie na wszystkich trzech osiach fizycznych (x, y i z), z wyłączeniem siły grawitacji. | monitorowanie przyspieszenia wzdłuż jednej osi; |
TYPE_MAGNETIC_FIELD |
Sprzęt | Mierzy otaczające pole geomagnetyczne na wszystkich 3 osiach fizycznych (x, y, z) w μT. | Tworzenie kompasu. |
TYPE_ORIENTATION |
Oprogramowanie | Mierzy stopnie obrotu urządzenia wokół wszystkich 3 osi fizycznych (x, y, z).
Od poziomu API 3 możesz uzyskać macierz nachylenia i macierz rotacji urządzenia, korzystając z czujnika grawitacji i czujnika pola geomagnetycznego w połączeniu z metodą getRotationMatrix() . |
określanie położenia urządzenia, |
TYPE_PRESSURE |
Sprzęt | Mierzy ciśnienie powietrza w hPa lub mbar. | monitorowanie zmian ciśnienia powietrza, |
TYPE_PROXIMITY |
Sprzęt | Mierzy odległość obiektu w centymetrach od ekranu urządzenia. Ten czujnik jest zwykle używany do określania, czy telefon jest trzymany przy uchu. | Pozycja telefonu podczas rozmowy. |
TYPE_RELATIVE_HUMIDITY |
Sprzęt | Mierzy względną wilgotność otoczenia w procentach (%). | Monitorowanie punktu rosy, wilgotności bezwzględnej i względnej. |
TYPE_ROTATION_VECTOR |
Oprogramowanie lub sprzęt | Mierzy orientację urządzenia, podając 3 elementy wektora rotacji urządzenia. | wykrywanie ruchu i obrotu, |
TYPE_TEMPERATURE |
Sprzęt | Mierzy temperaturę urządzenia w stopniach Celsjusza (°C). Implementacja tego czujnika różni się w zależności od urządzenia, a w API na poziomie 14 został on zastąpiony czujnikiem TYPE_AMBIENT_TEMPERATURE . |
monitorowanie temperatury, |
Platforma czujników
Dostęp do tych czujników i surowych danych z nich możesz uzyskać za pomocą platformy czujników Androida.
Platforma czujników jest częścią pakietu android.hardware
i zawiera te klasy i interfejsy:
SensorManager
- Za pomocą tej klasy możesz utworzyć instancję usługi czujnika. Ta klasa udostępnia różne metody uzyskiwania dostępu do czujników i wyświetlania ich listy, rejestrowania i wyrejestrowywania detektorów zdarzeń czujnika oraz uzyskiwania informacji o orientacji. Ta klasa udostępnia też kilka stałych czujnika, które służą do raportowania dokładności czujnika, ustawiania szybkości pozyskiwania danych i kalibrowania czujników.
Sensor
- Za pomocą tej klasy możesz utworzyć instancję konkretnego czujnika. Ta klasa udostępnia różne metody, które pozwalają określić możliwości czujnika.
SensorEvent
- System używa tej klasy do tworzenia obiektu zdarzenia czujnika, który zawiera informacje o zdarzeniu czujnika. Obiekt zdarzenia czujnika zawiera te informacje: surowe dane z czujnika, typ czujnika, który wygenerował zdarzenie, dokładność danych i sygnaturę czasową zdarzenia.
SensorEventListener
- Za pomocą tego interfejsu możesz utworzyć 2 metody wywołania zwrotnego, które będą otrzymywać powiadomienia (zdarzenia czujnika) o zmianach wartości czujnika lub jego dokładności.
W typowych aplikacjach używasz tych interfejsów API związanych z czujnikami do wykonywania 2 podstawowych zadań:
- Identyfikowanie czujników i ich możliwości
Identyfikowanie czujników i ich możliwości w czasie działania jest przydatne, jeśli aplikacja ma funkcje, które zależą od określonych typów czujników lub ich możliwości. Możesz na przykład zidentyfikować wszystkie czujniki obecne na urządzeniu i wyłączyć funkcje aplikacji, które korzystają z czujników, których nie ma na urządzeniu. Podobnie możesz chcieć zidentyfikować wszystkie czujniki danego typu, aby wybrać implementację czujnika, która zapewnia optymalną wydajność w Twojej aplikacji.
- Monitorowanie zdarzeń z czujników
Monitorowanie zdarzeń czujnika to sposób uzyskiwania nieprzetworzonych danych z czujnika. Zdarzenie czujnika występuje za każdym razem, gdy czujnik wykryje zmianę mierzonych parametrów. Zdarzenie czujnika zawiera 4 rodzaje informacji: nazwę czujnika, który wywołał zdarzenie, sygnaturę czasową zdarzenia, dokładność zdarzenia i surowe dane z czujnika, które wywołały zdarzenie.
Dostępność czujnika
Dostępność czujników zależy od urządzenia, ale może się też różnić w zależności od wersji Androida. Dzieje się tak, ponieważ czujniki Androida były wprowadzane w ramach kilku wersji platformy. Na przykład wiele czujników wprowadzono w Androidzie 1.5 (poziom interfejsu API 3), ale niektóre z nich nie zostały zaimplementowane i nie były dostępne do użycia aż do Androida 2.3 (poziom interfejsu API 9). Podobnie w Androidzie 2.3 (poziom interfejsu API 9) i Androidzie 4.0 (poziom interfejsu API 14) wprowadzono kilka czujników. Dwa czujniki zostały wycofane i zastąpione nowszymi, lepszymi czujnikami.
W tabeli 2 podsumowaliśmy dostępność poszczególnych czujników na poszczególnych platformach. Na liście znajdują się tylko 4 platformy, ponieważ tylko w ich przypadku wprowadzono zmiany w sensorach. Czujniki, które zostały oznaczone jako wycofane, są nadal dostępne na kolejnych platformach (pod warunkiem, że czujnik jest obecny na urządzeniu), co jest zgodne z zasadami dotyczącymi kompatybilności wstecznej Androida.
Tabela 2. Dostępność czujników na poszczególnych platformach.
Czujnik | Android 4.0 (poziom 14 interfejsu API) |
Android 2.3 (poziom API 9) |
Android 2.2 (poziom API 8) |
Android 1.5 (poziom API 3) |
---|---|---|---|---|
TYPE_ACCELEROMETER |
Tak | Tak | Tak | Tak |
TYPE_AMBIENT_TEMPERATURE |
Tak | nie dotyczy | nie dotyczy | nie dotyczy |
TYPE_GRAVITY |
Tak | Tak | nie dotyczy | nie dotyczy |
TYPE_GYROSCOPE |
Tak | Tak | n/a1 | n/a1 |
TYPE_LIGHT |
Tak | Tak | Tak | Tak |
TYPE_LINEAR_ACCELERATION |
Tak | Tak | nie dotyczy | nie dotyczy |
TYPE_MAGNETIC_FIELD |
Tak | Tak | Tak | Tak |
TYPE_ORIENTATION |
Tak2 | Tak2 | Tak2 | Tak |
TYPE_PRESSURE |
Tak | Tak | n/a1 | n/a1 |
TYPE_PROXIMITY |
Tak | Tak | Tak | Tak |
TYPE_RELATIVE_HUMIDITY |
Tak | nie dotyczy | nie dotyczy | nie dotyczy |
TYPE_ROTATION_VECTOR |
Tak | Tak | nie dotyczy | nie dotyczy |
TYPE_TEMPERATURE |
Tak2 | Tak | Tak | Tak |
1 Ten typ czujnika został dodany w Androidzie 1.5 (poziom interfejsu API 3), ale nie był dostępny do użycia do czasu wprowadzenia Androida 2.3 (poziom interfejsu API 9).
2 Ten czujnik jest dostępny, ale został wycofany.
Identyfikowanie czujników i ich możliwości
Platforma czujników Androida udostępnia kilka metod, które ułatwiają określanie w czasie działania, które czujniki są dostępne na urządzeniu. Interfejs API udostępnia też metody, które pozwalają określić możliwości każdego czujnika, takie jak maksymalny zakres, rozdzielczość i wymagania dotyczące zasilania.
Aby zidentyfikować czujniki na urządzeniu, musisz najpierw uzyskać odniesienie do usługi czujników. Aby to zrobić, utwórz instancję klasy SensorManager
, wywołując metodę getSystemService()
i przekazując argument SENSOR_SERVICE
. Na przykład:
Kotlin
private lateinit var sensorManager: SensorManager ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
Java
private SensorManager sensorManager; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Następnie możesz uzyskać listę wszystkich czujników na urządzeniu, wywołując metodę
getSensorList()
i używając stałej TYPE_ALL
. Na przykład:
Kotlin
val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)
Java
List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
Jeśli chcesz wyświetlić listę wszystkich czujników danego typu, możesz użyć innej stałej zamiast TYPE_ALL
, np. TYPE_GYROSCOPE
, TYPE_LINEAR_ACCELERATION
lub TYPE_GRAVITY
.
Możesz też sprawdzić, czy na urządzeniu znajduje się określony typ czujnika, używając metody getDefaultSensor()
i przekazując stałą typu dla konkretnego czujnika. Jeśli urządzenie ma więcej niż 1 czujnik danego typu, jeden z nich musi być oznaczony jako domyślny. Jeśli dla danego typu czujnika nie ma domyślnego czujnika, wywołanie metody zwraca wartość null, co oznacza, że urządzenie nie ma tego typu czujnika. Na przykład ten kod sprawdza, czy na urządzeniu jest magnetometr:
Kotlin
private lateinit var sensorManager: SensorManager ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) { // Success! There's a magnetometer. } else { // Failure! No magnetometer. }
Java
private SensorManager sensorManager; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){ // Success! There's a magnetometer. } else { // Failure! No magnetometer. }
Uwaga: Android nie wymaga od producentów urządzeń, aby wbudowywali w urządzenia z Androidem określone typy czujników, więc urządzenia mogą mieć różne konfiguracje czujników.
Oprócz wyświetlania listy czujników na urządzeniu możesz używać publicznych metod klasy
Sensor
, aby określać możliwości i atrybuty poszczególnych czujników. Jest to przydatne, jeśli chcesz, aby aplikacja działała inaczej w zależności od tego, które czujniki lub funkcje czujników są dostępne na urządzeniu. Możesz na przykład użyć metod getResolution()
i getMaximumRange()
, aby uzyskać rozdzielczość czujnika i maksymalny zakres pomiaru. Możesz też użyć metody
getPower()
, aby uzyskać informacje o wymaganiach dotyczących zasilania czujnika.
2 metody publiczne są szczególnie przydatne, jeśli chcesz zoptymalizować aplikację pod kątem czujników różnych producentów lub różnych wersji czujnika. Jeśli na przykład aplikacja musi monitorować gesty użytkownika, takie jak przechylanie i potrząsanie, możesz utworzyć jeden zestaw reguł filtrowania i optymalizacji danych dla nowszych urządzeń, które mają czujnik grawitacji określonego producenta, oraz drugi zestaw reguł filtrowania i optymalizacji danych dla urządzeń, które nie mają czujnika grawitacji, a tylko akcelerometr. Poniższy przykładowy kod pokazuje, jak możesz to zrobić za pomocą metod getVendor()
i getVersion()
. W tym przykładzie szukamy czujnika grawitacyjnego, którego dostawcą jest Google LLC i który ma numer wersji 3. Jeśli danego czujnika nie ma na urządzeniu, próbujemy użyć akcelerometru.
Kotlin
private lateinit var sensorManager: SensorManager private var mSensor: Sensor? = null ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) { val gravSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY) // Use the version 3 gravity sensor. mSensor = gravSensors.firstOrNull { it.vendor.contains("Google LLC") && it.version == 3 } } if (mSensor == null) { // Use the accelerometer. mSensor = if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) { sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) } else { // Sorry, there are no accelerometers on your device. // You can't play this game. null } }
Java
private SensorManager sensorManager; private Sensor mSensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mSensor = null; if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){ List<Sensor> gravSensors = sensorManager.getSensorList(Sensor.TYPE_GRAVITY); for(int i=0; i<gravSensors.size(); i++) { if ((gravSensors.get(i).getVendor().contains("Google LLC")) && (gravSensors.get(i).getVersion() == 3)){ // Use the version 3 gravity sensor. mSensor = gravSensors.get(i); } } } if (mSensor == null){ // Use the accelerometer. if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){ mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); } else{ // Sorry, there are no accelerometers on your device. // You can't play this game. } }
Inną przydatną metodą jest getMinDelay()
, która zwraca minimalny interwał czasowy (w mikrosekundach), w jakim czujnik może odczytywać dane. Każdy czujnik, który zwraca niezerową wartość w przypadku metody getMinDelay()
, jest czujnikiem przesyłającym strumieniowo dane. Czujniki strumieniowe odczytują dane w regularnych odstępach czasu. Zostały wprowadzone w Androidzie 2.3 (poziom interfejsu API 9). Jeśli czujnik zwraca zero po wywołaniu metody getMinDelay()
, oznacza to, że nie jest to czujnik strumieniowy, ponieważ raportuje dane tylko wtedy, gdy nastąpi zmiana w parametrach, które mierzy.
Metoda getMinDelay()
jest przydatna, ponieważ pozwala określić maksymalną szybkość, z jaką czujnik może zbierać dane. Jeśli niektóre funkcje aplikacji wymagają wysokiej częstotliwości pozyskiwania danych lub przesyłania strumieniowego z czujnika, możesz użyć tej metody, aby sprawdzić, czy czujnik spełnia te wymagania, a następnie odpowiednio włączyć lub wyłączyć odpowiednie funkcje w aplikacji.
Uwaga: maksymalna częstotliwość pozyskiwania danych przez czujnik nie musi być częstotliwością, z jaką platforma czujników dostarcza dane z czujnika do aplikacji. Platforma czujników przekazuje dane za pomocą zdarzeń czujnika, a na częstotliwość, z jaką aplikacja otrzymuje zdarzenia czujnika, wpływa kilka czynników. Więcej informacji znajdziesz w artykule Monitorowanie zdarzeń z czujników.
Monitorowanie zdarzeń czujnika
Aby monitorować surowe dane z czujników, musisz zaimplementować 2 metody wywołania zwrotnego, które są udostępniane przez interfejs SensorEventListener
: onAccuracyChanged()
i onSensorChanged()
. System Android wywołuje te metody, gdy wystąpią te zdarzenia:
- Zmienia się dokładność czujnika.
W takim przypadku system wywołuje metodę
onAccuracyChanged()
, przekazując odwołanie do obiektuSensor
, który uległ zmianie, oraz nową dokładność czujnika. Dokładność jest reprezentowana przez jedną z 4 stałych stanu:SENSOR_STATUS_ACCURACY_LOW
,SENSOR_STATUS_ACCURACY_MEDIUM
,SENSOR_STATUS_ACCURACY_HIGH
lubSENSOR_STATUS_UNRELIABLE
. - Czujnik zgłasza nową wartość.
W takim przypadku system wywołuje metodę
onSensorChanged()
, przekazując obiektSensorEvent
. ObiektSensorEvent
zawiera informacje o nowych danych z czujnika, w tym dokładność danych, czujnik, który je wygenerował, sygnaturę czasową, w której zostały wygenerowane, oraz nowe dane zarejestrowane przez czujnik.
Poniższy kod pokazuje, jak używać metody onSensorChanged()
do monitorowania danych z czujnika światła. W tym przykładzie surowe dane z czujnika są wyświetlane w elemencie TextView
, który jest zdefiniowany w pliku main.xml jako sensor_data
.
Kotlin
class SensorActivity : Activity(), SensorEventListener { private lateinit var sensorManager: SensorManager private var mLight: Sensor? = null public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) } override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) { // Do something here if sensor accuracy changes. } override fun onSensorChanged(event: SensorEvent) { // The light sensor returns a single value. // Many sensors return 3 values, one for each axis. val lux = event.values[0] // Do something with this sensor value. } override fun onResume() { super.onResume() mLight?.also { light -> sensorManager.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL) } } override fun onPause() { super.onPause() sensorManager.unregisterListener(this) } }
Java
public class SensorActivity extends Activity implements SensorEventListener { private SensorManager sensorManager; private Sensor mLight; @Override public final void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); } @Override public final void onAccuracyChanged(Sensor sensor, int accuracy) { // Do something here if sensor accuracy changes. } @Override public final void onSensorChanged(SensorEvent event) { // The light sensor returns a single value. // Many sensors return 3 values, one for each axis. float lux = event.values[0]; // Do something with this sensor value. } @Override protected void onResume() { super.onResume(); sensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); } }
W tym przykładzie domyślne opóźnienie danych (SENSOR_DELAY_NORMAL
) jest określane podczas wywoływania metody registerListener()
. Opóźnienie danych (lub częstotliwość próbkowania) określa interwał, w którym zdarzenia czujnika są wysyłane do aplikacji za pomocą metody wywołania zwrotnego onSensorChanged()
. Domyślne opóźnienie danych jest odpowiednie do monitorowania typowych zmian orientacji ekranu i wynosi 200 000 mikrosekund. Możesz określić inne opóźnienia danych, np. SENSOR_DELAY_GAME
(opóźnienie 20 000 mikrosekund), SENSOR_DELAY_UI
(opóźnienie 60 000 mikrosekund) lub SENSOR_DELAY_FASTEST
(opóźnienie 0 mikrosekund). Od Androida 3.0 (interfejs API na poziomie 11) możesz też określić opóźnienie jako wartość bezwzględną (w mikrosekundach).
Określone przez Ciebie opóźnienie jest tylko sugestią. System Android i inne aplikacje mogą zmienić to opóźnienie. Zalecamy określenie jak największego opóźnienia, ponieważ system zwykle używa mniejszego opóźnienia niż podane przez Ciebie (czyli wybierz najwolniejsze próbkowanie, które nadal spełnia potrzeby Twojej aplikacji). Użycie dłuższego opóźnienia powoduje mniejsze obciążenie procesora, a tym samym mniejsze zużycie energii.
Nie ma publicznej metody określania szybkości, z jaką platforma czujników wysyła zdarzenia czujników do aplikacji. Możesz jednak użyć sygnatur czasowych powiązanych z każdym zdarzeniem czujnika, aby obliczyć częstotliwość próbkowania na podstawie kilku zdarzeń. Po ustawieniu częstotliwości próbkowania (opóźnienia) nie powinno być konieczne jej zmienianie. Jeśli z jakiegoś powodu musisz zmienić opóźnienie, musisz wyrejestrować i ponownie zarejestrować odbiornik czujnika.
Warto też zauważyć, że w tym przykładzie do rejestrowania i wyrejestrowywania odbiornika zdarzeń czujnika używane są metody wywołania zwrotnego onResume()
i onPause()
. Zgodnie ze sprawdzoną metodą zawsze wyłączaj czujniki, których nie potrzebujesz, zwłaszcza gdy Twoja aktywność jest wstrzymana. Jeśli tego nie zrobisz, bateria może się wyczerpać w ciągu kilku godzin, ponieważ niektóre czujniki mają znaczne wymagania dotyczące zasilania i mogą szybko zużywać energię baterii. System nie wyłączy automatycznie czujników, gdy ekran się wyłączy.
Obsługa różnych konfiguracji czujników
Android nie określa standardowej konfiguracji czujników dla urządzeń, co oznacza, że producenci mogą w swoich urządzeniach z Androidem stosować dowolną konfigurację czujników. Dzięki temu urządzenia mogą zawierać różne czujniki w wielu konfiguracjach. Jeśli aplikacja korzysta z określonego typu czujnika, musisz się upewnić, że jest on dostępny na urządzeniu, aby aplikacja mogła działać prawidłowo.
Aby mieć pewność, że dany czujnik jest obecny na urządzeniu, masz 2 możliwości:
- wykrywać czujniki w czasie działania i włączać lub wyłączać funkcje aplikacji w zależności od potrzeb;
- Używaj filtrów Google Play, aby kierować reklamy na urządzenia z określonymi konfiguracjami czujników.
Każda z tych opcji jest omówiona w kolejnych sekcjach.
Wykrywanie czujników w czasie działania
Jeśli aplikacja korzysta z określonego typu czujnika, ale nie jest od niego zależna, możesz użyć platformy czujników, aby wykryć czujnik w czasie działania, a następnie włączyć lub wyłączyć funkcje aplikacji w zależności od potrzeb. Na przykład aplikacja do nawigacji może używać czujnika temperatury, czujnika ciśnienia, czujnika GPS i czujnika pola geomagnetycznego do wyświetlania temperatury, ciśnienia atmosferycznego, lokalizacji i kierunku kompasu. Jeśli urządzenie nie ma czujnika ciśnienia, możesz użyć platformy czujników, aby wykryć brak czujnika ciśnienia w czasie działania, a następnie wyłączyć część interfejsu aplikacji, która wyświetla ciśnienie. Na przykład ten kod sprawdza, czy na urządzeniu jest czujnik ciśnienia:
Kotlin
private lateinit var sensorManager: SensorManager ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null) { // Success! There's a pressure sensor. } else { // Failure! No pressure sensor. }
Java
private SensorManager sensorManager; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null){ // Success! There's a pressure sensor. } else { // Failure! No pressure sensor. }
Używanie filtrów Google Play do kierowania na konkretne konfiguracje czujników
Jeśli publikujesz aplikację w Google Play, możesz użyć elementu <uses-feature>
w pliku manifestu, aby odfiltrować urządzenia, które nie mają odpowiedniej konfiguracji czujników dla Twojej aplikacji. Element
<uses-feature>
zawiera kilka deskryptorów sprzętu, które umożliwiają filtrowanie aplikacji na podstawie obecności określonych czujników. Możesz podać te czujniki: akcelerometr, barometr, kompas (pole geomagnetyczne), żyroskop, czujnik światła i czujnik zbliżeniowy. Oto przykładowy wpis w pliku manifestu, który filtruje aplikacje bez akcelerometru:
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
Jeśli dodasz ten element i deskryptor do pliku manifestu aplikacji, użytkownicy zobaczą Twoją aplikację w Google Play tylko wtedy, gdy ich urządzenie będzie miało akcelerometr.
Deskryptor android:required="true"
należy ustawić tylko wtedy, gdy aplikacja
w całości zależy od konkretnego czujnika. Jeśli aplikacja używa czujnika do niektórych funkcji, ale nadal działa bez niego, należy umieścić czujnik w elemencie <uses-feature>
, ale ustawić deskryptor na android:required="false"
. Dzięki temu urządzenia będą mogły zainstalować Twoją aplikację nawet wtedy, gdy nie mają danego czujnika. Jest to też sprawdzona metoda zarządzania projektami, która pomaga śledzić funkcje używane przez aplikację.
Pamiętaj, że jeśli Twoja aplikacja korzysta z określonego czujnika, ale działa również bez niego, musisz wykrywać czujnik w czasie działania i włączać lub wyłączać funkcje aplikacji w odpowiedni sposób.
Układ współrzędnych czujnika
Ogólnie rzecz biorąc, platforma czujników używa standardowego 3-osiowego układu współrzędnych do wyrażania wartości danych. W przypadku większości czujników układ współrzędnych jest zdefiniowany względem ekranu urządzenia, gdy jest ono trzymane w domyślnej orientacji (patrz rysunek 1). Gdy urządzenie jest trzymane w domyślnej orientacji, oś X jest pozioma i skierowana w prawo, oś Y jest pionowa i skierowana w górę, a oś Z jest skierowana na zewnątrz ekranu. W tym systemie współrzędne za ekranem mają ujemne wartości Z. Ten układ współrzędnych jest używany przez te czujniki:

Rysunek 1. Układ współrzędnych (względem urządzenia) używany przez interfejs Sensor API.
- Czujnik przyspieszenia
- Czujnik grawitacji
- Żyroskop
- Czujnik przyspieszenia liniowego
- Czujnik pola geomagnetycznego
Najważniejszą rzeczą, którą należy wiedzieć o tym układzie współrzędnych, jest to, że osie nie są zamieniane, gdy zmienia się orientacja ekranu urządzenia. Oznacza to, że układ współrzędnych czujnika nigdy się nie zmienia, gdy urządzenie jest w ruchu. Działa to tak samo jak w przypadku układu współrzędnych OpenGL.
Kolejna ważna kwestia to to, że aplikacja nie może zakładać, że naturalna (domyślna) orientacja urządzenia to orientacja pionowa. W przypadku wielu tabletów naturalną orientacją jest orientacja pozioma. Układ współrzędnych czujnika jest zawsze oparty na naturalnej orientacji urządzenia.
Jeśli aplikacja dopasowuje dane z czujnika do wyświetlanych na ekranie, musisz użyć metody getRotation()
, aby określić obrót ekranu, a następnie metody remapCoordinateSystem()
, aby zmapować współrzędne czujnika na współrzędne ekranu. Musisz to zrobić nawet wtedy, gdy plik manifestu określa wyświetlanie tylko w orientacji pionowej.
Uwaga: niektóre czujniki i metody używają układu współrzędnych, który jest powiązany z globalnym układem odniesienia (w przeciwieństwie do układu odniesienia urządzenia). Te czujniki i metody zwracają dane, które reprezentują ruch urządzenia lub jego położenie względem Ziemi. Więcej informacji znajdziesz w artykule o metodzie getOrientation()
, metodzie getRotationMatrix()
, czujniku orientacji i czujniku wektora rotacji.
Ograniczanie szybkości czujnika
Aby chronić potencjalnie poufne informacje o użytkownikach, jeśli Twoja aplikacja jest kierowana na Androida 12 (poziom API 31) lub nowszego, system ogranicza częstotliwość odświeżania danych z niektórych czujników ruchu i czujników położenia. Te dane obejmują wartości zarejestrowane przez akcelerometr, żyroskop i czujnik pola geomagnetycznego urządzenia.
Limit częstotliwości odświeżania zależy od sposobu uzyskiwania dostępu do danych z czujników:
- Jeśli wywołasz metodę
registerListener()
w celu monitorowania zdarzeń czujnika, częstotliwość próbkowania czujnika będzie ograniczona do 200 Hz. Dotyczy to wszystkich przeciążonych wariantów metodyregisterListener()
. - Jeśli używasz klasy
SensorDirectChannel
, częstotliwość próbkowania czujnika jest ograniczona doRATE_NORMAL
, czyli zwykle około 50 Hz.
Jeśli aplikacja musi zbierać dane z czujnika ruchu z większą częstotliwością, musisz zadeklarować uprawnienie HIGH_SAMPLING_RATE_SENSORS
, jak pokazano w tym fragmencie kodu. Jeśli aplikacja próbuje zbierać dane z czujnika ruchu z większą częstotliwością bez deklarowania tego uprawnienia, wystąpi SecurityException
.
AndroidManifest.xml
<manifest ...> <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/> <application ...> ... </application> </manifest>
Sprawdzone metody uzyskiwania dostępu do czujników i korzystania z nich
Podczas projektowania implementacji czujnika pamiętaj o przestrzeganiu wytycznych omówionych w tej sekcji. Te wytyczne zawierają zalecane sprawdzone metody dla wszystkich osób, które korzystają z platformy czujników, aby uzyskiwać dostęp do czujników i danych z nich pochodzących.
Zbieranie danych z czujników tylko na pierwszym planie
Na urządzeniach z Androidem 9 (poziom interfejsu API 28) lub nowszym aplikacje działające w tle podlegają tym ograniczeniom:
- Czujniki, które korzystają z trybu raportowania ciągłego, takie jak akcelerometry i żyroskopy, nie otrzymują zdarzeń.
- Czujniki, które korzystają z trybów raportowania on-change lub one-shot, nie otrzymują zdarzeń.
Ze względu na te ograniczenia najlepiej wykrywać zdarzenia czujnika, gdy aplikacja jest na pierwszym planie lub w ramach usługi na pierwszym planie.
Wyrejestrowywanie detektorów czujników
Po zakończeniu korzystania z czujnika lub gdy jego aktywność zostanie wstrzymana, należy wyrejestrować jego odbiornik. Jeśli odbiornik czujnika jest zarejestrowany, a jego aktywność jest wstrzymana, czujnik będzie nadal zbierać dane i zużywać baterię, dopóki nie wyrejestrujesz czujnika. Poniższy kod pokazuje, jak użyć metody onPause()
do wyrejestrowania odbiornika:
Kotlin
private lateinit var sensorManager: SensorManager ... override fun onPause() { super.onPause() sensorManager.unregisterListener(this) }
Java
private SensorManager sensorManager; ... @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); }
Więcej informacji znajdziesz na stronie unregisterListener(SensorEventListener)
.
Testowanie w emulatorze Androida
Emulator Androida zawiera zestaw wirtualnych elementów sterujących czujnikami, które umożliwiają testowanie czujników, takich jak akcelerometr, czujnik temperatury otoczenia, magnetometr, czujnik zbliżeniowy, czujnik światła i inne.
Emulator korzysta z połączenia z urządzeniem z Androidem, na którym działa aplikacja SdkControllerSensor. Pamiętaj, że ta aplikacja jest dostępna tylko na urządzeniach z Androidem 4.0 (API na poziomie 14) lub nowszym. (Jeśli urządzenie ma Androida 4.0, musi mieć zainstalowaną wersję 2). Aplikacja SdkControllerSensor monitoruje zmiany w czujnikach na urządzeniu i przesyła je do emulatora. Emulator jest następnie przekształcany na podstawie nowych wartości otrzymywanych z czujników na urządzeniu.
Kod źródłowy aplikacji SdkControllerSensor możesz wyświetlić w tym miejscu:
$ your-android-sdk-directory/tools/apps/SdkController
Aby przenieść dane między urządzeniem a emulatorem, wykonaj te czynności:
- Sprawdź, czy na urządzeniu włączone jest debugowanie USB.
- Podłącz urządzenie do komputera deweloperskiego za pomocą kabla USB.
- Uruchom aplikację SdkControllerSensor na urządzeniu.
- W aplikacji wybierz czujniki, które chcesz emulować.
Uruchom to polecenie
adb
:- Uruchom emulator. Teraz możesz przekształcać emulator, przesuwając urządzenie.
$ adb forward tcp:1968 tcp:1968
Uwaga: jeśli ruchy wykonywane na urządzeniu fizycznym nie przekładają się na zmiany w emulatorze, spróbuj ponownie wykonać adb
polecenie z kroku 5.
Więcej informacji znajdziesz w przewodniku po emulatorze Androida.
Nie blokuj metody onSensorChanged()
Dane z czujnika mogą się zmieniać z dużą częstotliwością, co oznacza, że system może dość często wywoływać metodę onSensorChanged(SensorEvent)
. Zalecamy, aby w metodzie onSensorChanged(SensorEvent)
wykonywać jak najmniej działań, aby jej nie blokować. Jeśli aplikacja wymaga filtrowania lub zmniejszania ilości danych z czujników, należy to robić poza metodą onSensorChanged(SensorEvent)
.
Unikanie wycofanych metod i rodzajów czujników
Wycofaliśmy kilka metod i stałych.
W szczególności wycofaliśmy TYPE_ORIENTATION
typ czujnika. Aby uzyskać dane o orientacji, użyj metody getOrientation()
. Podobnie wycofaliśmy typ czujnika TYPE_TEMPERATURE
. Na urządzeniach z Androidem 4.0 należy używać typu czujnika TYPE_AMBIENT_TEMPERATURE
.
Sprawdzanie czujników przed użyciem
Zanim spróbujesz uzyskać dane z czujnika, zawsze sprawdzaj, czy jest on dostępny na urządzeniu. Nie zakładaj, że czujnik istnieje tylko dlatego, że jest często używany. Producenci urządzeń nie muszą umieszczać w nich żadnych konkretnych czujników.
Rozważnie wybieraj opóźnienia czujnika
Podczas rejestrowania czujnika za pomocą metody registerListener()
wybierz szybkość dostarczania odpowiednią dla Twojej aplikacji lub przypadku użycia. Czujniki mogą dostarczać dane z bardzo dużą częstotliwością. Zezwolenie systemowi na wysyłanie dodatkowych danych, których nie potrzebujesz, powoduje marnowanie zasobów systemowych i zużywanie baterii.