Ok, da sich das als besonders schwierige Frage herausgestellt hat, dachte ich, ich würde hier meine Lösung posten, falls irgendjemand etwas Ähnliches trifft.
Es gibt eindeutig mehrere Möglichkeiten, dies zu erreichen, aber das einfachste, das ich verwendet habe, ist einen "gestarteten" Dienst zu haben, der entscheidet, wann er sich selbst herunterfährt. Meine Aktivitäten binden/binden an den Dienst, und nach einer gewissen Zeitverzögerung (ich habe 1 Minute benutzt) schaltet sich der Dienst ab, wenn keine weiteren Aktivitäten gebunden sind - dies gilt, wenn der Benutzer die App nicht mehr verwendet, und wenn dies der Fall ist irgendwelche fatalen Aktivitätsfehler.
Der Shutdown-Timer wird innerhalb onUnbind()
geplant und wird in onStartCommand()
, onBind()
, onRebind()
abgebrochen. Wenn es ausgelöst wird, wird der Dienst sauber heruntergefahren, was wiederum eine Bereinigung des verwalteten Status im Dienst onDestroy()
des Dienstes auslöst.
Mein Service
Code ist wie folgt:
public class LocalStateService extends Service {
/** The binder to give to clients. */
private final IBinder binder = new LocalStateBinder();
/** Used for time-delayed shutdown. */
private final Handler handler = new Handler();
/**
* Called before starting or the first binding.
*/
@Override
public void onCreate() {
// initialise state...
}
/**
* Called when this service is explicitly started.
* @param intent The intent passed on starting, unused
* @param flags Startup flags, unused
* @param startId Identifies each start request
* @return Desired restart behaviour
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
cancelShutdown();
// if killed, we would like Android to restart this service, but don't bother re-delivering
// the original intent used to start the service
return START_STICKY;
}
/**
* Called when the first client binds.
* @param intent The intent passed on binding
* @return The binding to use
*/
@Override
public IBinder onBind(Intent intent) {
cancelShutdown();
return binder;
}
/**
* Called when the first of previous clients re-binds.
* @param intent The intent passed on binding
*/
@Override
public void onRebind(Intent intent) {
cancelShutdown();
}
/**
* Called when all clients have unbound.
* @param intent The first intent originally passed on binding
* @return Whether this service should be notified of rebinding
*/
@Override
public boolean onUnbind(Intent intent) {
// post a callback to be run in 1 minute
handler.postDelayed(delayedShutdown, 1000L * 60);
// we do want onRebind called when clients return
return true;
}
@Override
public void onDestroy() {
// state cleanup...
}
private Runnable delayedShutdown = new Runnable() {
@Override
public void run() {
LocalStateService.this.stopSelf();
}
};
/**
* Cancel any shutdown timer that may have been set.
*/
private void cancelShutdown() {
// remove any shutdown callbacks registered
handler.removeCallbacks(delayedShutdown);
}
}
Statt dies zu tun aus meiner Application
, meine Haupttätigkeit startService(..)
in onCreate()
da dies erfordert sowohl für die Erstinbetriebnahme arbeiten und wenn der Benutzer geht ein auf die Verwendung pausierte App (wo der Dienst sich vielleicht entschieden hat, sich selbst zu schließen).
Jede Aktivität bindet und löst dann wie normal.
Ich fand, dass:
Wenn zwischen den Aktivitäten der Navigation, wird kein Service Rückruf gefeuert. Da die Aktivität Lebenszyklus überlappt, sind diese sekundären bind/entbindet
Wenn eine Aktivität neu gestartet wird (zB Bildschirm-Rotation), wird der Dienst eine onUnbind()
dann eine onRebind()
Anruf
Bei Anhalten der App (zB Presse zu Hause aus Haupttätigkeit) oder beim Abschluss (z. B.drücken Sie zurück von der Hauptaktivität), der Dienst wird onUnbind()
dann wird der Timer ausgelöst.
Ich werde irgendwann mehr daran arbeiten müssen. Ich vermeide es, wie die Pest zu binden, also habe ich kein Muster, das dein Problem angehen könnte, und anscheinend war der Rat, den ich dir gegeben habe, fehlerhaft. – CommonsWare
Wie wäre es mit ein paar Bind/Unbind Funktionalität zu meiner 'Application' Instanz hinzufügen - erhöhen/dekrementieren einen internen Zähler und nur tatsächlich einmal binden/lösen? – cjn
Es ist möglich, dass das funktioniert, obwohl es ein bisschen riskant ist (z. B. nicht behandelte Ausnahmen, die dazu führen, dass Sie nicht dekrementieren). – CommonsWare