2017-03-23 5 views
0

Ich habe hier ein kleines Problem, ich weiß nicht, wie ich es lösen soll.Android tötet den Dienst, nachdem der Tag vorbei ist?

Ich benutze einen einfachen Dienst, der einen StepDetector registriert (nicht Counter, da ich mich selbst um Steps kümmern möchte). Es wird Sticky gestartet.

Außerdem habe ich einen BroadcastReceiver implementiert. Es wartet auf BOOT_Completed und Service_Destroyed. Soweit ich das beurteilen kann, funktioniert es großartig, wenn man die App neu startet oder die App beendet. Es zählt und speichert Daten in der Realm-Datenbank.

Noch etwas weiter: Ich speichere die Step-Data in zwei Tabellen.

  1. speichern sie auf einer perHour-Basis, was bedeutet, dass jeder Schritt in der corespodonding Stunden-Reihe geschrieben genommen wird. Beispiel: Stunden 5-60 Demarchen Stunden 7-30 Demarchen

  2. speichert sie auf einem perday-Basis. Hier werden alle an diesem Tag durchgeführten Schritte gespeichert.

Mein onStartCommand so aussieht:

manager = (SensorManager)getSystemService(SENSOR_SERVICE); 
    stepDetectorSensor = manager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR); 
    manager.registerListener(this, stepDetectorSensor, SensorManager.SENSOR_DELAY_FASTEST); 

    return Service.START_STICKY; 

Das ist mein onSensorChanged

if(stamp == 0){ 
     stamp = event.timestamp; 
    } 
    if(stamp != event.timestamp) { 

     RealmConfiguration config = new RealmConfiguration.Builder() 
       .deleteRealmIfMigrationNeeded() 
       .build(); 
     Realm realm = Realm.getInstance(config); 

     realm.executeTransaction(new Realm.Transaction() { 
      @Override 
      public void execute(Realm realm) { 
       Date date = new Date(); 

       DailyValues dailyValues = realm.where(DailyValues.class).equalTo("type", DailyValues.STEPS).findAll() 
         .where().equalTo("Day", date.getDay()).findAll() 
         .where().equalTo("Month", date.getMonth()).findAll() 
         .where().equalTo("Year", date.getYear()).findFirst(); 


       ValuesPerHour valuesPerHour = realm.where(ValuesPerHour.class).equalTo("type", ValuesPerHour.STEPS).findAll() 
         .where().equalTo("hour", date.getHours()).findAll() 
         .where().equalTo("day", date.getDay()).findFirst(); 

       if (dailyValues != null) { 
        dailyValues.Value += 1; 
       } else { 
        RealmResults<ValuesPerHour> row = realm 
          .where(ValuesPerHour.class).equalTo("type", ValuesPerHour.STEPS).findAll() 
          .where().notEqualTo("day",date.getDay()).findAll(); 
        row.deleteAllFromRealm(); 
        dailyValues = realm.createObject(DailyValues.class); 
        dailyValues.Day = date.getDay(); 
        dailyValues.Month = date.getMonth(); 
        dailyValues.Year = date.getYear(); 
        dailyValues.Value = 1; 
        dailyValues.type = dailyValues.STEPS; 

       } 

       if (valuesPerHour != null) 
        valuesPerHour.value += 1; 
       else { 
        valuesPerHour = realm.createObject(ValuesPerHour.class); 
        valuesPerHour.value = 1; 
        valuesPerHour.hour = date.getHours(); 
        valuesPerHour.day = date.getDay(); 
        valuesPerHour.type = valuesPerHour.STEPS; 
       } 


      } 
     }); 
     stamp = event.timestamp; 
    } 

Es ist nicht die endgültige Version, so könnte es einige Konstruktionsfehler sein, aber wie Sie sehen können, Ich schaue ob da schon Daten für "Heute" von Tag Monat und Jahr bestimmt werden. Wenn dies der Fall ist, fügen Sie einen Schritt hinzu. Wenn nicht, füge eine Zeile hinzu, füge einen Schritt hinzu und lösche perHour-Table. Dann mache ich fast gleich mit der perHour-Table, um es zu aktualisieren.

Mein onDestroy()

super.onDestroy(); 
    Intent broadcastIntent = new Intent(".RestartSensor"); 
    sendBroadcast(broadcastIntent); 

sendet einfach die Restart Sachen. Und last but not least, die Empfänger OnReceive-Methode:

context.startService(new Intent(context, StepCounterService.class)); 
     Log.i("Restart", "Restarted"); 

Manifest ist auch gut, wie ich Schritt zählt auf Kraft-Schließen und Neustarten von Telefon zu bekommen. Die einzige Sache, die mich verrückt macht, ist, dass, wenn ein neuer Tag dort ist, und ich anfange, das Telefon zu bewegen, ohne die Anwendung zuerst zu starten, keine Schritte registriert werden. Erst nach dem Start der App funktioniert alles wieder gut.

Bearbeiten: Recht ATM Ich benutze StartForeground, um dieses Problem zu vermeiden. Aber Apps wie sHealth erhalten dies ohne eine klebrige Benachrichtigung. Also im Grunde würde ich gerne wissen, wie man einen Dienst neu startet, egal was passiert.

Wie in den Kommentaren erwähnt, wird onDestroy nicht immer aufgerufen, so dass ein Neustart nicht garantiert ist. Ein anderes Problem könnte sein, dass Android die App in den Schlaf versetzt (?), Also brauche ich vielleicht einen Wakelock?

Ich glaube nicht, dass es über die Lese-/Schreib-Methode geht, da es in jeder anderen Situation funktioniert.

+0

Es ist nicht garantiert, dass onDestroy wird aufgerufen, wenn ein Dienst getötet wird –

+0

so wie kann ich das beheben? –

+0

Ich habe keine Zeit oder Motivation, um in Ihren Fall zu graben. Geben Sie nur einige Informationen –

Antwort

0

Nun, ich denke, ich habe es jetzt funktioniert. Ich hoffe, jemand wird kommentieren, wenn etwas falsch oder schlecht ist. Bitte, wenn Sie etwas sehen, helfen Sie mir, es zu beheben. Ich muss auch wissen, ob dieser Ansatz zu stark auf die Batterie ableitet.

Mein Ansatz hat zwei Mechanismen im Empfänger arbeiten.

  1. Einen WakefulBroadcastReceiver verwenden und startWakefulService verwenden.
  2. Set Alarmmanager in OnReceive() aufrufen OnReceive alle 5 Sekunden

Das ist mein OnReceive() - Methode:

AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 
    Intent intentReciever = new Intent(context, SensorRestartBroadcastReceiver.class); 
    PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intentReciever, 0); 
    alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 5*1000, 
      5*1000, alarmIntent); 


    if(isServiceRunning(context,StepCounterService.class) == false){ 
     sMonitorServiceIntent = new Intent(context, StepCounterService.class); 
     startWakefulService(context,sMonitorServiceIntent); 
     Log.i("BroadcastReceiver", "Restarted"); 
    } 
    else{ 
     Log.i("BroadcastReceiver", "Is running"); 
    } 

Wie Sie sehen, ist isServiceRunning aufgerufen, die so aussieht:

ActivityManager am = (ActivityManager) context 
      .getSystemService(Context.ACTIVITY_SERVICE); 
    for (ActivityManager.RunningServiceInfo serviceInfo : am 
      .getRunningServices(Integer.MAX_VALUE)) { 
     String className1 = serviceInfo.service.getClassName(); 
     String className2 = serviceClass.getName(); 
     if (className1.equals(className2)) { 
      return true; 
     } 
    } 
    return false; 

Es prüft einfach, ob eine Instanz dieses Service bereits läuft. Falls nicht, starten Sie den Dienst neu, sonst ist nichts zu tun.

Problem ist: ATM Ich starte den Dienst über die MainActivity und speichern eine Instanz. So kann ich Service.Stop aufrufen, um onDestroy im Service zu initiieren.

Wenn ich den Dienst über Broadcast starte, der von der Aktivität aufgerufen wird, kann ich Service.Stop nicht aufrufen, was dazu führt, dass der Dienst sich nicht neu erstellt. Ich habe es versucht. Wenn Sie Aktivität -> Broadcast -> Service verwenden, wird kein Wert angezeigt, wenn der Dienst oder die App beendet wird.

Mein aktueller Ansatz ist das Einchecken von MainActivity, wenn Service ausgeführt wird. Wenn nicht, führe es aus. Der Dienst ruft den ersten Aufruf des Empfängers in onStartCommand() auf, um sicherzustellen, dass der Empfänger gestartet wird.

Verwandte Themen