Im vorherigen Kapitel haben wir das Auslesen von Sensordaten auf einem physischen Gerät demonstriert, wobei der Lichtsensor verwendet wurde. In diesem Kapitel wenden wir uns den Magnetfeld- und Beschleunigungssensoren zu, um die Richtung des magnetischen Nordpols zu berechnen und diese Information zur Animation eines Kompasses auf dem Gerät zu nutzen. Während die Rohdaten der Magnetfeldsensoren leicht zugänglich sind, sind sie allein nicht besonders anschaulich. Erst die Kombination dieser Daten mit denen des Beschleunigungssensors ermöglicht eine sinnvolle Darstellung, wie der Kompass auf die Bewegung des Geräts reagiert.

Vorbereitung

Zunächst müssen wir ein neues Projekt in Android Studio erstellen und es „Compass“ nennen. Es wird empfohlen, die Standardoptionen für Smartphones und Tablets zu verwenden und eine leere Aktivität zu wählen. Für die Anzeige des Kompasses benötigen wir ein Bild, das wir im Ressourcenordner res/drawable ablegen. Ein transparentes Bild, das speziell für die Drehung optimiert ist, ist vorteilhaft, aber nicht zwingend erforderlich. Ein Beispielbild könnte von Pixabay heruntergeladen werden: https://pixabay.com/en/geography-map-compass-rose-plot-42608/.

Nachdem wir das Bild bereitgestellt haben, gehen wir weiter zu den erforderlichen Codierungen. Wir öffnen die Datei activity_main.xml und ersetzen die bestehende TextView durch ein ImageView, das unser Kompassbild anzeigen soll. In der MainActivity.java fügen wir dann einige globale Variablen hinzu, die für die Sensoren und die Animation benötigt werden.

Sensoren und EventListener

Für die Sensorsteuerung verwenden wir die SensorManager-Klasse, um die Sensordaten des Magnetometers und des Beschleunigungssensors zu erhalten. Dazu deklarieren wir die benötigten Variablen:

java
private SensorManager mSensorManager;
private Sensor mMagnetometer; private Sensor mAccelerometer; private ImageView mImageViewCompass; private float[] mGravityValues = new float[3];
private float[] mAccelerationValues = new float[3];
private float[] mRotationMatrix = new float[9];
private float mLastDirectionInDegrees = 0f;

Im nächsten Schritt fügen wir einen SensorEventListener hinzu, der auf Sensoränderungen reagiert. Der Listener wird in der onSensorChanged()-Methode aufgerufen, um die Kompassrichtung zu berechnen:

java
private SensorEventListener mSensorListener = new SensorEventListener() { @Override
public void onSensorChanged(SensorEvent event) {
calculateCompassDirection(event); }
@Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // Keine Aktion erforderlich } };

Aktivierung und Registrierung der Sensoren

Die Sensoren müssen im onResume()-Methodenaufruf registriert und im onPause()-Methodenaufruf wieder abgemeldet werden, um eine kontinuierliche Überwachung zu gewährleisten:

java
@Override
protected void onResume() { super.onResume(); mSensorManager.registerListener(mSensorListener, mMagnetometer, SensorManager.SENSOR_DELAY_FASTEST); mSensorManager.registerListener(mSensorListener, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST); } @Override protected void onPause() { super.onPause(); mSensorManager.unregisterListener(mSensorListener); }

Berechnung der Kompassrichtung

Die calculateCompassDirection()-Methode verwendet die Sensorwerte, um die Ausrichtung des Geräts in Bezug auf das magnetische Nord zu berechnen. Dabei wird die getRotationMatrix()-Methode des SensorManager genutzt, um eine Rotationsmatrix zu berechnen, die anschließend durch getOrientation() in Orientierungswerte umgewandelt wird. Das Ergebnis wird als Azimut in Grad zurückgegeben:

java
private void calculateCompassDirection(SensorEvent event) { switch (event.sensor.getType()) { case Sensor.TYPE_ACCELEROMETER: mAccelerationValues = event.values.clone(); break; case Sensor.TYPE_MAGNETIC_FIELD: mGravityValues = event.values.clone(); break; }
boolean success = SensorManager.getRotationMatrix(mRotationMatrix, null, mAccelerationValues, mGravityValues);
if (success) { float[] orientationValues = new float[3]; SensorManager.getOrientation(mRotationMatrix, orientationValues);
float azimuth = (float)Math.toDegrees(-orientationValues[0]);
RotateAnimation rotateAnimation = new RotateAnimation( mLastDirectionInDegrees, azimuth, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setDuration(50); rotateAnimation.setFillAfter(true); mImageViewCompass.startAnimation(rotateAnimation); mLastDirectionInDegrees = azimuth; } }

Der Azimut, der die Richtung des magnetischen Nordpols angibt, wird in Grad umgewandelt und für die Animation des Kompasses verwendet. Die RotateAnimation wird erstellt, wobei das Bild des Kompasses in der Mitte rotiert, und wir speichern den aktuellen Azimut für die nächste Berechnung.

Zusätzliche Überlegungen

Obwohl das Beispiel eine sehr schnelle Animation erzeugt, indem es sowohl den Sensor-Update-Intervall als auch die Animationsdauer minimiert, können Sie experimentieren, um andere visuelle Effekte zu erzielen. Die Wahl des Sensordatenintervalls sowie der Animationsgeschwindigkeit kann variieren, um unterschiedliche Effekte zu erzielen, die möglicherweise für Ihre Anwendung nützlicher sind.

Die SENSOR_DELAY_FASTEST-Option sorgt für die schnellstmögliche Verarbeitung der Sensordaten, aber in manchen Fällen könnte es sinnvoller sein, die Sensordaten langsamer zu aktualisieren und eine sanftere Animation zu wählen, um die Benutzererfahrung zu optimieren. Wichtig ist auch, dass die App auf echten Geräten mit Magnetometer und Beschleunigungssensor getestet wird, da der Emulator keine entsprechenden physikalischen Sensoren simuliert.

Wie man mit Google API Fehlern umgeht und Standortaktualisierungen erhält

In modernen Android-Anwendungen, die Google APIs verwenden, kommt es oft vor, dass die API-Verbindung fehlschlägt, etwa weil der Google API-Client nicht richtig verbunden ist oder veraltete Bibliotheken verwendet werden. Statt einfach eine Fehlermeldung an den Benutzer zu senden, bietet sich eine bessere Lösung an: die Verwendung der GoogleApiAvailability-Bibliothek, um dem Benutzer zu helfen, das Problem direkt zu lösen. Dies erhöht nicht nur die Benutzerfreundlichkeit der Anwendung, sondern sorgt auch dafür, dass der Benutzer nicht ohne Erklärung auf der Fehlerseite zurückgelassen wird.

Im Rahmen dieses Kapitels bauen wir auf einem bereits bestehenden Beispiel auf, in dem wir den Google API-Client nutzen, um den letzten Standort des Nutzers zu erhalten. Wenn der API-Client jedoch beim Verbindungsaufbau auf Probleme stößt, müssen wir nicht nur auf die Fehler reagieren, sondern auch aktiv eingreifen, um die Verbindung wiederherzustellen. Der folgende Abschnitt erläutert, wie man mit einer Fehlverbindung des Google API-Clients und der Fehlerbehandlung in der onConnectionFailed()-Methode umgehen kann.

Zunächst erweitern wir unsere Hauptaktivität um eine Methode zur Anzeige eines Fehlerdialogs. Dieser Dialog wird angezeigt, wenn der Google API-Client aufgrund einer veralteten oder nicht funktionsfähigen Verbindung einen Fehler meldet. Die Verwendung des GoogleApiAvailability-Dialogs hilft dabei, das Problem zu beheben, indem der Benutzer gegebenenfalls die erforderlichen Berechtigungen oder Einstellungen auf seinem Gerät anpasst. Dies ist eine benutzerfreundlichere Methode, als lediglich eine Toast-Nachricht zu verwenden, die dem Benutzer nicht genügend Informationen gibt, um den Fehler zu beheben.

Ein wichtiger Schritt in diesem Zusammenhang ist das Hinzufügen einer Fehlerbehandlungsroutine in der onConnectionFailed()-Methode. Diese Methode überprüft zunächst, ob der Fehler durch eine einfache Aktion des Nutzers behoben werden kann, wie beispielsweise das Aktivieren von Standortdiensten. Falls dies nicht möglich ist, wird der GoogleApiAvailability-Dialog aufgerufen, um den Benutzer direkt auf das Problem hinzuweisen und ihm eine Möglichkeit zur Fehlerbehebung zu bieten.

Zusätzlich zur Fehlerbehandlung können Sie in der onActivityResult()-Methode überprüfen, ob der Fehler behoben wurde und ob der Google API-Client erneut verbunden werden kann. Dies stellt sicher, dass die Anwendung ohne manuelles Eingreifen des Entwicklers fortgesetzt werden kann, sobald das Problem gelöst ist. Diese Methode ist besonders nützlich, wenn der Benutzer eine Aktion ausführt, um den Fehler zu beheben, beispielsweise das Aktivieren von Standortdiensten oder das Aktualisieren der Google Play-Dienste.

Ein weiterer wichtiger Aspekt ist, dass das Testen dieser Funktionalität auf realen Geräten von Vorteil ist. Insbesondere auf Geräten mit veralteten Versionen von Google APIs können Fehler auftreten, die mit Emulatoren schwer nachzuvollziehen sind. Es ist ratsam, solche Tests regelmäßig durchzuführen, um sicherzustellen, dass die Fehlerbehandlung korrekt funktioniert und der Benutzer bei Bedarf unterstützt wird.

Ein weiteres Thema, das in modernen Android-Anwendungen von Bedeutung ist, ist die kontinuierliche Aktualisierung des Standorts des Nutzers. Dies kann für Anwendungen notwendig sein, die präzise und aktuelle Standortinformationen erfordern, wie etwa Navigations- oder Fitness-Apps. Die requestLocationUpdates()-Methode des Google API Clients ermöglicht es, regelmäßige Standortaktualisierungen zu erhalten, die in einer Textansicht oder einer anderen Benutzeroberfläche angezeigt werden können.

In diesem Kontext ist es ebenfalls entscheidend, die richtigen Berechtigungen für die Standorterfassung zu definieren und sicherzustellen, dass der Nutzer diese Berechtigungen gewährt. Der Zugriff auf Standortdaten ist ein sensibles Thema und muss sowohl aus Datenschutzgründen als auch aus praktischen Gründen korrekt gehandhabt werden. Die Implementierung der LocationListener-Klasse ermöglicht es, den Standort kontinuierlich zu überwachen und diese Informationen bei Bedarf in der Benutzeroberfläche darzustellen. Dabei ist es ratsam, für eine effiziente Nutzung der Ressourcen den Standort nur in festgelegten Intervallen zu aktualisieren.

Zusätzlich zur regelmäßigen Standortaktualisierung gibt es in einigen Fällen auch die Notwendigkeit, einen Geofence zu implementieren. Geofencing ermöglicht es einer App, Benachrichtigungen zu senden, wenn der Benutzer ein bestimmtes geografisches Gebiet betritt oder verlässt. Um dies zu realisieren, müssen Entwickler zusätzlich zum Standortzugriff auch Geofence-Dienste nutzen. Hierbei kommt es darauf an, den Geofence richtig zu definieren und sicherzustellen, dass die Benutzer über die verwendeten Funktionen und die damit verbundenen Berechtigungen informiert sind.

Es ist wichtig, dass der Entwickler bei der Arbeit mit Standortdaten und Google APIs stets auf die Aktualität der verwendeten Bibliotheken achtet. Änderungen in den Google-Diensten und APIs können dazu führen, dass ältere Methoden nicht mehr unterstützt werden oder zu unerwarteten Problemen führen. Daher sollte regelmäßig geprüft werden, ob die verwendeten Versionen der Google Play-Dienste und der zugehörigen APIs auf dem neuesten Stand sind, um die bestmögliche Performance und Kompatibilität sicherzustellen.