GPS updates auch bei ausgeschaltetem Bildschirm

  • Antworten:20
  • Bentwortet
Slarti Bartfast
  • Forum-Beiträge: 12

17.08.2018, 18:49:21 via Website

Hallihallo,
ich habe mir ein kleines Projekt vorgenommen: ich möchte eine App schreiben, die meine Geschwindigkeit beim Fahradfahren monitored und speichert. Das ganze gefitzel mit dem Gps hab ich hin bekommen, eigentlich funktioniert alles, ABER:
Wenn mein smartphone den bildschirm ausschaltet, macht das handy keine location updates mehr. gibt es eine möglichkeit, wie ich die updates im hintergrund auch mit ausgeschalteten bildschirm weiterlaufen lassen kann?

Vielen dank schon mal im vorraus :)

Kommentieren
Beste Antwort
swa00
  • Forum-Beiträge: 3.704

21.08.2018, 22:11:41 via Website

Du bist auf dem richtigen Weg , jetzt haste auch zu viel gemacht :-)

Ich habe Dir mal was herausgesucht
http://informationideas.com/news/2012/03/06/how-to-keep-an-android-service-running/

Übergib einfach dem AlarmManger deine Serviceklasse und schon ist der Drops gelutscht :-)

— geändert am 21.08.2018, 22:52:41

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Kommentieren
swa00
  • Forum-Beiträge: 3.704

17.08.2018, 18:53:41 via Website

Hallo,

Dann müsstest du das Ganze in einen Service verlagern.
Bsp : http://www.vogella.com/tutorials/AndroidServices/article.html

ABER : Android wird dir auch Diesen nach einen Weile nach Lust und Laune beenden , denn
Android ist nicht dazu konzipiert 24/7 Apps /Services laufen zu lassen.
Dazu müsstest du dir als Workaround einen Heartbeat bauen.

Siehe auch dazu Stichpunkte wie Lifecycle und GarbageCollector

— geändert am 17.08.2018, 21:22:47

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Kommentieren
Slarti Bartfast
  • Forum-Beiträge: 12

17.08.2018, 21:27:05 via Website

Hey,
Vielen dank für deine schnelle Antwort. Jetzt weis ich, wie ich weiter machen muss.
Das mit dem heartbeat sagt mir leider noch nichts. Könntest du mir das noch kurz erläutern?

Hilfreich?
Kommentieren
swa00
  • Forum-Beiträge: 3.704

17.08.2018, 21:30:47 via Website

Wie oben erklärt , kann Android auch Die den Service abschalten.
Dies ist ungewiss, ob und wann das passiert - das steuert das System.

Eine Abhilfe wäre es ggf. einen AlarmManager zu benutzen ,der den Service beendet und danach wieder startet. Quasi einen Herzschlag = Heartbeat.

— geändert am 17.08.2018, 23:43:32

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Kommentieren
Slarti Bartfast
  • Forum-Beiträge: 12

18.08.2018, 15:55:43 via Website

Hey, ich hab das mit dem service mal probiert. Leider stoppen immer noch die gps updates, wenn ich eine andere app benutze oder den bildschirm sperre.
ich hab euch mal den code meines Services mit rangehangen, vlt findet ihr ja einen fehler.

package com.example.slartibartfast.kslordered;

import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.util.Log;

public class BackroundService extends Service {

private static float speed;


//initializing the Location Manager and Listener
private LocationManager locationManager;
private LocationListener locationListener;



@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //Instantiating the device manager an  listener
    locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    locationListener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            //when the location changed

            Log.d("Location", ""+location);
            Log.d("Float Location", ""+ location.getLongitude() + "     " + location.getLatitude());
            Log.d("Speed", "    "+location.getSpeed());

            //initializing the variable speed with the speed number given by the LocationListener
            speed = location.getSpeed();
            MainActivity.getSpeedFromService();

            //writes speed in the textview

        }


        @Override
        public void onStatusChanged(String s, int i, Bundle bundle) {

        }


        @Override
        public void onProviderEnabled(String s) {

        }


        @Override
        public void onProviderDisabled(String s) {
            //if gps is disabled, this opens the gps settings
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            startActivity(intent);
        }
    };
    locationManager.requestLocationUpdates("gps", 500, 0, locationListener);


    return START_STICKY;
}

public static float getSpeed() {
    return speed;
}

}

Vielen Dank für die Hilfe :)

Hilfreich?
Kommentieren
swa00
  • Forum-Beiträge: 3.704

18.08.2018, 16:26:30 via Website

Hallo, du hast so einige Fehler drin .

Schau dir das mal an
https://stackoverflow.com/a/44630033/6337627

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Kommentieren
Slarti Bartfast
  • Forum-Beiträge: 12

19.08.2018, 19:27:49 via Website

ich bin noch ein ziemlicher Anfänger. Ich werde aus dem Code nicht wirklich schlau.
muss ich denn noch mehr machen, außer den Code, der im Hintergrund ausgeführt werden soll, in onStartCommand geschrieben wird und diese START_STICKY zurückgeben soll.

Hilfreich?
Kommentieren
Jokel
  • Forum-Beiträge: 1.527

19.08.2018, 20:26:59 via Website

Hi
Also in deinem Code kann ich nichts erkenn was in irgend einer form den Service neu startet.
Kein Timer oder dergleichen. Wahrscheinlich machst du das in der Activity. Wenn dem so ist , ist schon mal klar warum der Service nicht mehr arbeitet wenn die Activity pausirt.

Zu dem Beispiel.
Da es passieren kann das ein Service vom System gekillt wild.

Wird da ein Broadcastresiever verwendet, der von einem Alarmmanager aller ca. 30sek aufgerufen wird .
Dies stellt den Heartbeat dar.
Ein Broadcastreciever der im Manifest erstellt wurde wird nicht so schnell vom System gekillt.
Dieser reciever ruft den Service auf.

Der Service startet einen Timer der den Reciever in dem gewünschten Intervall aufruft.

Der allarmmanager wird in der Main gestartet mit ständiger Wiederholung.
Somit ist der Heartbeat gesichert.

Ich hoffe du kannst jetzt den Code etwas besser verstehen.

— geändert am 19.08.2018, 20:55:35

Hilfreich?
Pascal P.
Kommentieren
Slarti Bartfast
  • Forum-Beiträge: 12

21.08.2018, 14:43:02 via Website

ok, vielen dank für die erklärung.
ich denke ich habe es verstanden:
Der alarmmanager in der main startet alle 30s einen broadcast, der wird von dem alrmreciever empfangen und dieser startet dann den service.
Was aber, wenn die main geschlossen wird? dann sendet der alarmmanager doch nicht mehr, oder?

Hilfreich?
Kommentieren
swa00
  • Forum-Beiträge: 3.704

21.08.2018, 14:50:32 via Website

Es tut mir ja leid, aber du hast es nicht verstanden.

a) Der Alarmmanger ist systemübergreifend (Bitte API lesen)
b) Alle 30 Sekunden ist also Blödsinn - setzt ihn mal auf eine Stunde

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Kommentieren
Jokel
  • Forum-Beiträge: 1.527

21.08.2018, 16:02:51 via Website

@saw00 nur zur Info in deinem Beispiel ist der Alarmmanager auf 30000 also 30 sek. gestellt habe nur versucht den Code etwas zu erklären. Die Quelle kam von Dir.
Ob nun 30 sek sinnvoll ist steht auf einem anderen Blatt.

Hilfreich?
Kommentieren
Slarti Bartfast
  • Forum-Beiträge: 12

21.08.2018, 16:31:01 via Website

Also muss ich in meiner Main einen AlarmManager initialisieren. was genau macht dann bzw. ist dieser pendingIntent?
Der Alarmmanager in der main sendet dann alle 30 sekunden einen Alarm an den Alarm reciever. Dieser führt dann den service erneut aus.
Stoppt das ganze dann nicht, wenn die main geschlossen wird?

Hilfreich?
Kommentieren
swa00
  • Forum-Beiträge: 3.704

21.08.2018, 16:56:58 via Website

Na dann zur Erklärung :-)

Der Alarmmaneger soll sicherstellen , dass der Service nicht vom System beendet wird und dann Nichts mehr erfolgt .
Innerhalb 30-60 Minuten passiert i.d.R. Nichts ..

@TE
Nein, der Alarmmanger ist ein SystemTool, du setzt ihn nur mit deiner Activity.

— geändert am 21.08.2018, 17:06:20

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Kommentieren
Slarti Bartfast
  • Forum-Beiträge: 12

21.08.2018, 22:01:02 via Website

erstmal vielen dank, das ihr mir das so geduldig erklärt.
Ich hatte mir das auch schon gedacht, das 30 sekunden schwachsinn ist. hab ihn bei mir auf ne halbe stunde gestellt.
ich habe versucht das jetzt so umzusetzen:
in der main:

@Override
protected void onResume() {
    super.onResume();

    if (alarmManager == null) {
        alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(this, AlarmReceive.class);
        pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1800000, pendingIntent);
    }

Alarm reciever:

 @Override
public void onReceive(Context context, Intent intent) {
    Intent backgroundService = new Intent(context, BackroundService.class);
    context.stopService(backgroundService);
    context.startService(backgroundService);
}

Da der AlarmManager ein SystemTool ist muss ich den wahrscheinlich auch in der onCreate instanzieren, oder?

So wie ich es jetzt gemacht habe funktioniert es auf jeden fall nicht. Der Service wird trotzdem beendet.
Danke nochmal für eure Geduld, ich lerne gerade viel :)

Hilfreich?
Kommentieren
Jokel
  • Forum-Beiträge: 1.527

21.08.2018, 22:11:25 via Website

Hi was sollen diese beiden Zeilen
context.stopService(backgroundService);
context.startService(backgroundService);

Du erstellst einen intent in dem reciever aber abschicken tust du ihn nicht.

Hilfreich?
Kommentieren
Beste Antwort
swa00
  • Forum-Beiträge: 3.704

21.08.2018, 22:11:41 via Website

Du bist auf dem richtigen Weg , jetzt haste auch zu viel gemacht :-)

Ich habe Dir mal was herausgesucht
http://informationideas.com/news/2012/03/06/how-to-keep-an-android-service-running/

Übergib einfach dem AlarmManger deine Serviceklasse und schon ist der Drops gelutscht :-)

— geändert am 21.08.2018, 22:52:41

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Kommentieren
Slarti Bartfast
  • Forum-Beiträge: 12

21.08.2018, 22:42:29 via Website

Das letzte beispiel hab ich mal übernommen:

in der main:

@Override
protected void onResume() {
    super.onResume();



    if (alarmManager == null) {
        Intent intentBackroundService = new Intent(this, BackroundService.class);
        PendingIntent pendingIntentBackroundService = PendingIntent.getService(this, 0, intentBackroundService, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(pendingIntentBackroundService);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1800000, pendingIntentBackroundService);
    }

Dann hatte ich noch das problem, dass sich mein service in dem festgelegten intervall noch schliesen muss, da ich sonst doppelte daten übergeben kriege.
Das habe ich jetzt versucht mit einem Handler().postDelayed und der this.stopService() Methode zu lösen. Ist mir Instant Abgeschmiert.
lag an der this.stopService methode (zumindest sagt mir das die fehlermeldung). ist an der was falsch?
Oder killt die methode alarmManager.cancel(pendingIntentBackroundService); schon den service?
@jokel:
nach meinem verständnis benutze ich den Intent um den Service zuerst zu schließen und dann wieder zu starten. vlt liege ich da auch falsch :)

Hilfreich?
Kommentieren
Jokel
  • Forum-Beiträge: 1.527

22.08.2018, 07:45:24 via Website

Hallo
Der Alarmmanager muss nicht im Manifest eingetragen werden. Wenn du deinen gesetzten Alarm wieder löschst wird nur der Alarm gelöscht nicht der Service . der wird sich dann wohl von selbst beenden. Was ja momentan auch dein Problem ist.

Oder killt die methode alarmManager.cancel(pendingIntentBackroundService); schon den service?

nein das tut er nicht.

ag an der this.stopService methode (zumindest sagt mir das die fehlermeldung). ist an der was falsch?

Wo hast du das angewendet? Im Service da geht das nicht. Nur von auserhalb.
Im Service benutze stopSelf(); dafür.

Dann hatte ich noch das problem, dass sich mein service in dem festgelegten intervall noch schliesen muss, da ich sonst doppelte daten übergeben kriege.

Ja deshalb vorher prüfen ob der Service noch läuft. bevor du einen neuen locationListener erstellst.
Denn du arbeistest jetzt wohl mit einen Thread, wenn ich mir den Letzen Beispiel Link anschaue.

Füge mal in deinen Code ein par Log Zeilen ein um zu sehen ob überhaupt die Intens richtig ankommen und verarbeitet werden. Also im Reciever, im Service und nicht nur im Listner.

Frage wann oder wie schnell beendet sich den dein Service?

Wegen den beiden Intenst teste mal ob wirklich auch der Stopp Intent zuerst empfangen wird und dann wieder der Start Intent. kannst denen ja ein putextra mitgeben um es zu unterscheiden.

Eigentlich sollte es reichen wenn der Alarmmanager gleich deinen Service aufruft.
Du solltest auch in deinem Service testen ob er noch läuft oder ob er beendet war. Dann brauchst du ihn nicht beenden. Wenn er beendet war durchläufst du deinen intitProzess wenn nicht sollte es reichen wenn du wieder den Service verlässt .

Um zu sehen ob das System den Service beendet kannst du die Methode onDestroy() Überschreiben ,und ein Log einfügen .

Zu deinem LocationManager brauchst du wirklich diese hohe Widerholungsrate 500 msek
Das wird dein System sehr stark belasten und auch das könnte ein Grund sein warum das System die App so schnell beendet wenn es im Hindergrund ist. Deshalb auch die Frage wie lange überhaupt der Service ohne Heartbeat läuft..

Ps zu deinem PendingIntent ich benutze dafür keine Flags.
PendingIntent.getService(this, 0, intentBackroundService, 0);
In deinem fall brauchst du keine flags.

noch zur Info dieser Link von Saw00 http://informationideas.com/news/2012/03/06/how-to-keep-an-android-service-running/ scheint schon etwas älter zu sein.
Ein "setRepeating" beim AlarmManager ist bei den jetzigen Api Versionen auf minimum 1 min auch wenn du kleinere Werte angibst wir der meistens nur jede Minute geschickt.
Glaube ab „KitKat“ o. „Lollipop“ ist 1 min bei ständiger Wiederholung das kleinste.

— geändert am 22.08.2018, 08:59:54

Hilfreich?
Kommentieren
swa00
  • Forum-Beiträge: 3.704

22.08.2018, 09:01:11 via Website

@jokel

ich halte mich bewusst zurück , weil ich deine Linie nicht unterbrechen/durcheinander bringen mag.

@Slarti

Zu deinem LocationManager brauchst du wirklich diese hohe Widerholungsrate 500 msek

Da hat jokel absolut recht
500ms ist ein unding. 2 Sekunden reichen völlig aus - du sitzt ja nicht im Flugzeug.
Zumal du bei einer Accuarcy von +/. 2 Metern eh nur dann gewackel hättest.

Besser noch, wenn man nur auf Änderungen reagiert - also Bearing, oder Velocity.
Die Grunddaten der Antenne , also die NMEA-Sätze kommen schon im Millisekunden-Takt beim System an und verbraten schon jede menge Resourcen im Hintergrund.

Also auch in der onLocationChanged noch ein bisschen Abfangen und nur dann was machen , wenn es auch absolut Sinn macht .

BTW bitte beachte : Wenn nicht mindestens 3 Satelliten in Sichtweite sind , schaltet der LocationManager auf GSM um. Das heisst, dass die Genauigkeit auf +/- 20 Meter abfällt.
Wenn du das auch nicht abfängst - fährst du ZickZack :-)

Also brav nach Pythagoras nochmal einen Gegencheck machen.

— geändert am 22.08.2018, 09:10:47

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Kommentieren
Slarti Bartfast
  • Forum-Beiträge: 12

22.08.2018, 09:12:17 via Website

Das wichtige ist, dass registriert wird, wenn eine Bewegeung stattfindet und wie schnell diese ist. Das ganze muss sehr schnell reagieren können, deswegen habe ich die 500 milis eingetragen.
Gibt es eine möglichkeit auf veränderungen der geschwindigkeit zu reagieren ohne permanente Updates zu machen?

@jokel
Das mit den Log daten werde ich mal ausprobieren.

Hilfreich?
Kommentieren
swa00
  • Forum-Beiträge: 3.704

22.08.2018, 09:16:43 via Website

Gibt es eine möglichkeit auf veränderungen der geschwindigkeit zu reagieren ohne permanente Updates zu machen?

Du hast das System leider nicht ganz verstanden :

public void onLocationChanged(Location location) {

Das ist ein Listener , er liefert Dir also nur dann was , wenn er was Verändertes hat .
Du bist also der "Passive".

Wenn du es aktiv haben möchtest, dann musst du mit NMEA OHNE Location-Listener arbeiten
https://developer.android.com/reference/android/location/OnNmeaMessageListener

Dazu brauchst du aber einen Parser, der dir die Sentences auseinander nimmt
https://www.gpsinformation.org/dale/nmea.htm

NACHTRAG : Wichtig

Das wichtige ist, dass registriert wird, wenn eine Bewegeung stattfindet und wie schnell diese ist.

Damit bist du mit GPS eh an der falschen Stelle - dazu musst du den Beschleunigungssensor nehmen.
Und dann erst im nachhinein alle 2 Sek GPS auswerten.
https://developer.android.com/guide/topics/sensors/sensors_motion

P.S. Location.velocity ist KEINE Bewegung, erst recht nicht Beschleunigung und kommt im 1-2 Sekunden Takt - im triangularen GSM Verfahren allerdings überhaupt nicht.
(Siehe auch meinen vorherigen Beitrag)

— geändert am 22.08.2018, 20:04:58

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Kommentieren