wake-up-neo.com

Android: Einen Hintergrunddienst am Leben erhalten (Tod des Prozesses verhindern)

Ich habe einen Dienst, der definiert ist als:

public class SleepAccelerometerService extends Service implements SensorEventListener

Im Wesentlichen mache ich eine App, die die Aktivität des Beschleunigungsmessers aus verschiedenen Gründen überwacht, während der Benutzer mit seinem Telefon/Gerät auf dem Bett schläft. Dies ist ein langjähriger Dienst, der während der Nacht NICHT getötet werden darf. Abhängig davon, wie viele Hintergrund-Apps und periodische Prozesse in der Nacht stattfinden, bricht Android manchmal meinen Prozess ab und beendet dadurch meinen Dienst. Beispiel:

10-04 03:27:41.673: INFO/ActivityManager(1269): Process com.androsz.electricsleep (pid 16223) has died.
10-04 03:27:41.681: INFO/WindowManager(1269): WIN DEATH: Window{45509f98 com.androsz.electricsleep/com.androsz.electricsleep.ui.SleepActivity paused=false}

Ich möchte den Benutzer nicht dazu zwingen, "SleepActivity" oder eine andere Aktivität in meiner App als Vordergrund zu haben. Ich kann meinen Dienst nicht regelmäßig ausführen lassen, da er ständig auf SensorChanged abfängt.

Irgendwelche Tipps? Der Quellcode ist hier: http://code.google.com/p/electricsleep/

51
Jon Willis

Für Android 2.0 oder höher können Sie die startForeground() -Methode verwenden, um Ihren Dienst im Vordergrund zu starten.

Die Dokumentation sagt folgendes :

Ein gestarteter Dienst kann die API startForeground(int, Notification) verwenden, um den Dienst in einen Vordergrundzustand zu versetzen, in dem das System ihn als etwas ansieht, das dem Benutzer aktiv bekannt ist, und das daher nicht für das Beenden in Frage kommt, wenn der Arbeitsspeicher knapp ist. (Es ist theoretisch immer noch möglich, dass der Dienst durch die aktuelle Vordergrundanwendung unter extremem Speicherdruck beendet wird. In der Praxis sollte dies jedoch kein Problem darstellen.)

Dies ist hauptsächlich dafür gedacht, wenn das Beenden des Dienstes für den Benutzer störend sein würde, z. Wenn Sie einen Musik-Player-Dienst beenden, wird die Musikwiedergabe gestoppt.

Sie müssen ein Notification für die Methode angeben, die in der Benachrichtigungsleiste im Abschnitt Laufend angezeigt wird.

72
Dave Webb

Wenn Sie Ihren Dienst mit BIND_AUTO_CREATE an Aktivität binden, wird Ihr Dienst unmittelbar nach Zerstörung und Aufhebung Ihrer Bindung beendet. Es hängt nicht davon ab, wie Sie Ihre Methode zum Aufheben der Bindung von Diensten implementiert haben. Sie wird trotzdem beendet.

Die andere Möglichkeit besteht darin, den Dienst mit der Methode startService aus Ihrer Aktivität heraus zu starten. Selbst wenn Ihre Aktivität zerstört wird, wird Ihr Dienst nicht zerstört oder sogar angehalten, aber Sie müssen ihn bei Bedarf mit stopSelf/stopService anhalten/zerstören.

16
Witold Graca

Wie Dave bereits betonte , könnten Sie Ihre Service mit Vordergrundpriorität ausführen. Diese Vorgehensweise sollte jedoch nur angewendet werden, wenn dies unbedingt erforderlich ist, d. H., Wenn die Benutzererfahrung beeinträchtigt wird, wenn der Dienst von Android beendet wird. Dies ist, was der "Vordergrund" wirklich bedeutet: Ihre App ist irgendwie im Vordergrund und der Benutzer würde es sofort bemerken, wenn sie getötet wird (z. B. weil sie ein Lied oder ein Video abgespielt hat).

In den meisten Fällen ist das Anfordern der Vordergrundpriorität für Ihren Dienst kontraproduktiv!

Warum das? Wenn Android beschließt, eine Service zu töten, geschieht dies, weil die Ressourcen knapp werden (normalerweise RAM). Basierend auf den verschiedenen Prioritätsklassen entscheidet Android, welche laufenden Prozesse und damit verbundene Dienste beendet werden, um Ressourcen freizugeben. Dies ist ein gesunder Prozess, den Sie durchführen möchten, damit der Benutzer eine reibungslose Erfahrung hat. Wenn Sie ohne triftigen Grund Vordergrundpriorität anfordern, um zu verhindern, dass Ihr Dienst beendet wird, führt dies höchstwahrscheinlich zu einer schlechten Benutzererfahrung. Oder können Sie sicherstellen, dass Ihr Service einen minimalen Ressourcenverbrauch aufweist und keine Speicherverluste aufweist?1

Android bietet sticky services, um Dienste zu kennzeichnen, die nach einer gewissen Nachfrist neu gestartet werden sollten, wenn sie getötet wurden. Dieser Neustart erfolgt normalerweise innerhalb weniger Sekunden.

Bild, das Sie einen XMPP-Client für Android schreiben möchten. Sollten Sie die Vordergrundpriorität für die Service anfordern, die Ihre XMPP-Verbindung enthält? Auf jeden Fall nein, es gibt absolut keinen Grund, dies zu tun. Sie möchten jedoch START_STICKY Als Rückgabeflag für die Methode onStartCommand Ihres Service verwenden. Damit Ihr Dienst bei Ressourcendruck gestoppt und neu gestartet wird, sobald die Situation wieder normal ist.

1: Ich bin mir ziemlich sicher, dass viele Android Apps Speicherverluste aufweisen. Es ist etwas, das den Gelegenheits- (Desktop-) Programmierern nicht so wichtig ist.

11
Flow

Ich hatte ein ähnliches Problem. Auf einigen Geräten nach einer Weile Android beendet meinen Dienst und sogar startForeground () hilft nicht. Und mein Kunde mag dieses Problem nicht. Meine Lösung ist zu verwenden - AlarmManager Klasse, um sicherzustellen, dass der Dienst ausgeführt wird, wenn es erforderlich ist. Ich verwende AlarmManager , um eine Art Watchdog-Timer zu erstellen. Von Zeit zu Zeit wird überprüft, ob der Dienst ausgeführt werden soll und starte es neu. Außerdem verwende ich SharedPreferences , um das Flag zu behalten, ob der Dienst ausgeführt werden soll.

Watchdog-Timer erstellen/schließen:

void setServiceWatchdogTimer(boolean set, int timeout)
{
    Intent intent;
    PendingIntent alarmIntent;
    intent = new Intent(); // forms and creates appropriate Intent and pass it to AlarmManager
    intent.setAction(ACTION_WATCHDOG_OF_SERVICE);
    intent.setClass(this, WatchDogServiceReceiver.class);
    alarmIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager am=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
    if(set)
        am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeout, alarmIntent);
    else
        am.cancel(alarmIntent);
}

Empfangen und Verarbeiten der Absicht vom Watchdog-Timer:

/** this class processes the intent and
 *  checks whether the service should be running
 */
public static class WatchDogServiceReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {

        if(intent.getAction().equals(ACTION_WATCHDOG_OF_SERVICE))
        {
            // check your flag and 
            // restart your service if it's necessary
            setServiceWatchdogTimer(true, 60000*5); // restart the watchdogtimer
        }
    }
}

In der Tat verwende ich WakefulBroadcastReceiver anstelle von BroadcastReceiver . Ich habe Ihnen den Code mit BroadcastReceiver gegeben, um ihn zu vereinfachen.

5
ivan

http://developer.Android.com/reference/Android/content/Context.html#BIND_ABOVE_CLIENT

public static final int BIND_ABOVE_CLIENT - Hinzugefügt in API Level 14

Flag für bindService(Intent, ServiceConnection, int): Gibt an, dass die Clientanwendung, die an diesen Dienst gebunden ist, den Dienst für wichtiger hält als die App selbst. Wenn diese Option aktiviert ist, versucht die Plattform, die App vor dem Beenden des Dienstes, an den sie gebunden ist, von dem Killer für nicht genügend Arbeitsspeicher zu beenden. Dies kann jedoch nicht garantiert werden.

Andere Flags derselben Gruppe sind: BIND_ADJUST_WITH_ACTIVITY, BIND_AUTO_CREATE, BIND_IMPORTANT, BIND_NOT_FOREGROUND, BIND_WAIVE_PRIORITY.

Beachten Sie, dass sich die Bedeutung von BIND_AUTO_CREATE in ICS geändert hat und alte Anwendungen, die nichts angebenBIND_AUTO_CREATE hat automatisch die FlagsBIND_WAIVE_PRIORITY undBIND_ADJUST_WITH_ACTIVITY für sie einstellen.

Ich arbeite an einer App und habe das Problem, meinen Service durch einen App-Kill zu beenden. Ich habe bei Google recherchiert und festgestellt, dass ich es in den Vordergrund stellen muss. Folgendes ist der Code:

public class UpdateLocationAndPrayerTimes extends Service {

 Context context;
@Override
public void onCreate() {
    super.onCreate();
    context = this;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    StartForground();
    return START_STICKY;
}

@Override
public void onDestroy() {


    super.onDestroy();
}

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


private void StartForground() {
    LocationChangeDetector locationChangeDetector = new LocationChangeDetector(context);
    locationChangeDetector.getLatAndLong();
    Notification notification = new NotificationCompat.Builder(this)
            .setOngoing(false)
            .setSmallIcon(Android.R.color.transparent)

            //.setSmallIcon(R.drawable.picture)
            .build();
    startForeground(101,  notification);

    }
}

Hoffentlich hilft es !!!!

2
Irfan Ul Haq

Halten Sie Ihren Service-Footprint klein, dies verringert die Wahrscheinlichkeit, dass Android=) Ihre Anwendung schließt. Sie können nicht verhindern, dass sie getötet wird, denn wenn Sie könnten, könnten die Leute leicht persistente Spyware erstellen

2
BeRecursive