Apps korrekt beenden - das warum und wie ..

  • Antworten:52
  • OffenNicht stickyNicht beantwortet
Gelöschter Account
  • Forum-Beiträge: 5.136

20.06.2009 00:21:54 via Website

Da mir in der letzten Zeit immer öfter Apps begegnen, die nicht korrekt oder gar nicht beendet werden, möchte ich hier mal in Kürze vorstellen warum man das tun sollte und wie man es tun kann.

Kurz zur Geschichte:
In der heutigen Zeit begegnet einem als Programmierer immer öfter Software, die sich aufgrund der stark gesunkenen Speicherpreise in keinster Weise mehr um Dinge wie Heap, Memory und Rechenleistung kümmern. Standardargument der meisten Programmierer : Ist ja eh genug Mem vorhanden .. da brauch ich mich heutzutage nicht mehr drum kümmern.

Stimmt das so ?
Nun ja .. das ist so ein Ding mit dem Speicher ... Theoretisch hat der Entwickler schon recht.

ABER: Meistens vergessen die Entwickler dabei zwei wesentliche Dinge. Erstens bewegt man sich heutzutage meistens in multiuser/multitasking Umgebungen.
Das bedeutet : Ich teile meinen Applikationsspeicher mit anderen Applikationen und/oder Threads, ausserdem belaste ich den Garbage Collector der JVM (Java Virtuellen Maschine) .

Ein Segen von Java, nämlich die Objektorientierung, kann in kritischen Fällen hier zum echten Hund werden. Einerseits gepriesen und viel verwendet, kann andererseits die gefankenlose Verwendung von Objekten schnell zum echten Speicherfresser werden. So Objekte können nämlich bei schlechter Planung ganz schnell ganz groß werden, ohne das man das im Single-User Testfall zunächst bemerkt.

Aber ich will nun nicht zu weit ins theoretische abschweifen ... zurück zum Thema.

Was kann ich also tun:
Zunächst etwas sehr simples, die eigene Anwendung zur rechten Zeit korrekt beenden und somit der JVM
erlauben aufzuräumen. Konkret also dem Garbage Collector zu ermöglichen, benötigen Speicher von nicht mehr
benötigten Variablen, Objekten und so weiter freizuräumen.

Den korrekten Zeitpunkt, wann eine App. beendet werden kann sollte jeder Programmierer kennen. Grob dann, wenn
die App. alle Aufgaben erledigt hat und die Lifetime der Activity beendet ist.

Wie das korrekt geht:

Ganz einfach, an der oder den richtigen Stellen eines oder beides der folgenden Dinge tun:

1. Aufruf der Methode
1finish();

Die Methode ist aus dem Paket android.app.Activity und propagiert das Ende der Activity an mögliche Aufrufer. Bestenfalls also an
das Betriebssystem selbst. Jedenfalls werden hiernach die benutzten Ressourcen finalisiert und freigegeben.

Es gibt auch noch Methoden um andere Activitys zu beenden, bzw. diese Events abzufragen. Darum soll es hier aber nicht gehen.

2. Zusätzlich kann man noch
1System.exit(0);
aufrufen.
Diese Methode aus dem Paket java.lang.System beendet relativ hart die momentane JVM und gibt Ressourcen wieder frei.
Ruft man vorher noch runFinalizersOnExit(true); auf, werden vor dem beenden der App. sämtliche Objekte hart vom
Garbage Collector erfasst, dereferenziert und finalisiert. Das sollte allerdings nur in echten Härtefällen
erfolgen, da ein Garbage Collector Lauf ein sogenanntes Dead Second bewirkt. Die Dead Second bedeutet nichts anderes
als das während des Garbage Collector Laufs die gesamte JVM STEHT weil nichts anderes mehr geht und NUR GC betrieben
wird. Dieser Prozess hat in jeder JVM TOP Priorität und kann in Härtefällen schon mal mehrere Minuten dauern.
Also VORSICHT mit dieser Option, auch wenn sie sicher alles wegputzt.

Also Leute .. finish(); und System.exit(0); tun nicht weh, das geht sogar in EINER ZEILE ... ;)

Warum ist das auf Systemen wie dem Android so wichtig?

Garbage Collection bedeutet CPU Zeit, Cpu Zeit = AkkuLeistung und AKKU .. hamma wenig
Wenig Speicher bedeutet mehr Garbage Collection, mehr Garbage Collection mehr CPU ... usw.

Ihr seht, dass sich soetwas sehr schnell aufschaukeln kann. Also denkt auch an Euer Android
und den armen Akku. Aber vor allem an die User die sich ärgern warum das Ding wieder mal
so elendiglich langsam geworden ist. Es liegt (vielleicht) auch mit an Euch ;)

In diesem Sinne, happy coding.

Nächstes Mal beschreibe ich dann wie man völlig simple mal nen Quit Menü in seine Apps einbauen
kann. Bis dahin ..

lg
voss

lg Voss

Petro HayeAnton S.Hartmut Schmidt

Antworten
  • Forum-Beiträge: 337

20.06.2009 02:23:24 via Website

Sehr kuhl Herr Voss ;)
Sollte auch unterstützt werden, denn es nervt nix mehr als ein Proggi das noch lebt obwohl man es schon lange nicht mehr benutzt ...

Antworten
Gelöschter Account
  • Forum-Beiträge: 5.136

20.06.2009 09:30:48 via Website

Danke Kevin,

aber sagt doch einfach Jörg .. :grin:

lg
Voss

lg Voss

Antworten
  • Forum-Beiträge: 337

21.06.2009 17:06:51 via Website

Schon klar ;)

ich varriere nur gerne in meinen anreden ... :D

Antworten
Gelöschter Account
  • Forum-Beiträge: 5.136

21.06.2009 17:58:59 via Website

Ok Sir Kevin :bashful:

Um zum Thema zurückzukommen

1finish();
2System.exit(OFF_TOPIC);


lg
Voss

— geändert am 21.06.2009 17:59:45

lg Voss

Antworten
  • Forum-Beiträge: 1.727

22.06.2009 11:22:39 via Website

Ist das seitens der Docu mit dem System.exit(id) irgendwo nachzulesen (Link bitte) ?

Habe meinerseits nirgends so was gelesen, stattdessen wird gesagt das in der Start Activity die finish Methode aufgerufen werden soll.

Wieso Ich das System.exit anzweifele ist daher begründet das die VM eine eigene Sandbox hat aber alle Apps doch in der gleichen VM laufen, daher würde ich erwarten das ein System.exit eine nicht implementiere Methode ist. Seit Java 5 ist das Class-Sharing allgemein verfügbar und Android nutzt das ja irgendwie auch, allerdings ist es in Java 5 so das wenn zwei Applikationen gleichzeitig in der JVM laufen und eine davon System.exit aufruft die andere plötzlich beendet, was zu Datenverlust führen kann.

Ich würde daher in meinen APPs von Activity eine Abstrakte Klasse ableiten und diese weiß welche die Start Activity ist. Rufe Ich nun finish auf einer dieser Klassen auf sollte das sauber sein.

- mac

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Gelöschter Account
  • Forum-Beiträge: 5.136

22.06.2009 13:24:19 via Website

Auf dem G1 läuft die sogn. Dalvik VM die gemeinsam mit dem darunterliegenden Linux-Kernel
so ausgelegt wurde, dass jede Applikation in einer eigenen VM-Instanz, bzw. einem eigenständigen
Linux Prozess läuft.
Diese VM, der Applikation wird mit einem system.exit(0) beendet, nichts anderes. Dabei werden
natürlich auch alle, wirklich alle Threads die mit dieser Applikation verknüpft sind, hart beendet.

Sollte eine Applikation derartige asynchrone Threads laufen haben muss man sich natürlich darum
kümmern diese vorher sauber zu beenden. Das finish() beendet lediglich die aktuelle Activity und die
mit ihr verbundenen laufenden Aktivitäten. Nicht unbedingt Threads die noch laufen und dann vielleicht
später noch nicht freigegebene Referenzen auf dem Stack hinterlassen.

Jedenfalls werden keinerlei andere VMs von dem in Deiner VM aufgerufenen system.exit() beeinflusst.

System.exit ist aus der java.lang.system und das ist dokumentiert, unter anderem, in der Android Developer
referenz unter: http://d.android.com/reference/java/lang/System.html#exit(int)

system.exit(0) geht absolut sicher, dass wirklich alles aufgeräumt wird durch den GC.
Das ist bei einem finish() nicht immer so unbedingt gesichert. Je nach Code implementierung eben.

voss

lg Voss

Antworten
  • Forum-Beiträge: 1.727

22.06.2009 13:42:11 via Website

Hmm, das werde Ich mir nachher mal ansehen. Wie sieht es denn aus wenn Ich eine Activity mittels finish() beende und meine Threads mittels #setDaemon(true) markiere ?

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Gelöschter Account
  • Forum-Beiträge: 5.136

22.06.2009 14:05:08 via Website

Keine Ahnung,

ich würde aber vermuten, dass die mit system.exit() ebenfalls gekillt werden.

voss

lg Voss

Antworten
  • Forum-Beiträge: 1.727

22.06.2009 17:40:36 via Website

Klar werden diese "gekillt" doch sind Daemon Threads in verbindung mit UI Toolkits gang und gäbe. Unter Swing / AWT z.b wird die JVM diese Threads einfach beenden sobald das UI "stirbt" bzw die Main methode letztendlich verlassen wird.

— geändert am 22.06.2009 17:47:44

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Gelöschter Account
  • Forum-Beiträge: 87

22.06.2009 20:23:40 via Website

Ich fand deinen Bericht sehr interessant wenn ich auch in einigen Punkten nicht so ganz zustimme.

Es ist wie du sagst sehr wichtig bei Systemen mit begrenztem Speicher und parallel laufenden Applikationen so effizient und speichersparend zu programmieren wie es nur geht.

Prinzipell jede Applikation mit finish() zu beenden halte ich jedoch in einigen Fällen für ziemlich kontraproduktiv. Insbesondere wenn die Applikation als Teil eines Tasks verwendet werden könnte.

Das schöne an Android ist ja genau das Task Konzept, wonach mittels Intents Funktionen von anderen Applikationen verwendet werden können die oft für den User nicht den Anschein haben als würde es eine andere Applikation sein. Wenn du nun deine Applikation mit finish() beendest und sie Teil eines Tasks war, machst du damit den gesamten Task des Users zunichte, weil er nicht mehr wie gewohnt mit seiner "Back" Taste zum vorherigem Screen wechseln kann.

Im Allgemeinen stört man damit das Konzept welches hinter Android steht. Solltest du eine volkommene Standalone App entwickeln die nie und nimmer an einem Task teilnimmt ist das vielleicht nicht ganz so schlimm, aber es kann trotzdem für den User unbefriedigend sein wenn er nicht wie gewohnt die "Back" Taste nutzen kann.

Nur mal so nachgedacht.

Antworten
  • Forum-Beiträge: 1.727

22.06.2009 20:46:25 via Website

@Abraxas Son: Was ist für dich ein Task ? Ein Thread ? Oder eine Activity die mittels Intent aufgerufen wurde ?

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Gelöschter Account
  • Forum-Beiträge: 87

23.06.2009 19:34:47 via Website

Mac Systems
@Abraxas Son: Was ist für dich ein Task ? Ein Thread ? Oder eine Activity die mittels Intent aufgerufen wurde ?


Ein Task ist ein Arbeitsgang in welchem mehrere Activities (auch über Applikationsgrenzen hinweg) involviert sind.

Aber wirklich genau definiert ist es unter folgendem Link:

Activity and Task Design

Antworten
Gelöschter Account
  • Forum-Beiträge: 5.136

24.06.2009 09:30:59 via Website

Hallo Abraxas,

natürlich nicht jede Applikation da gebe ich Dir völlig Recht
... theoretisch zumindest aber dazu gleich mehr.

Der Entwickler einer Applikation muss ja den Lebenszyklus seiner Anwendung genau
kennen. Nicht jede Anwendung arbeitet nun mit Threads und Hintergrundausführung.
Bspw. hab ich eine kleine App. geschrieben die nix anderes tut, als Wlan ein oder
auszuschalten. Die braucht theoretisch nicht mal ne View, weil sie über einen view-unabhängigen
Toast nur eine kurze Bestätigung dessen ausgibt was sie nun gemacht hat.
Die wird sofort nach Ausführung wieder korrekt beendet und dümpelt nicht länger
im Speicher herum.

Schreibe ich nun aber eine Applikation die auf SystemBroadcasts reagiert oder eine Api
für andere Applikationen bereitstellt, dann muss ich mir ggf. sehr wohl Gedanken darum
machen ob überhaupt und wann ich eine Applikation wie beende. Gebe ich dem Benutzer die Möglichkeit
über einen Quit Button, mache ich das von einem Systemzustand abhängig, oder gar von der
Anwesenheit anderer Applikationen im Prozesskontext, oder oder oder.

Ich wurde bis jetzt mangels entsprechender Herausforderung noch nicht direkt mit dem
LifeCycle Konzept von Android konfrontiert, werde aber jetzt wohl daran gehen müssen
dieses näher zu ergründen weil ich so einen Background task benötigen werde.
Ich werd dann mal berichten was ich mir da so zu ausgedacht habe.

Das mit der Backtaste .. ist sicherlich auch Teil des gesamten Android LifCycle
Managements. Hier kommen die Funktionen onDestroy onPause onRestart und wie sie
heissen ins Spiel. Diese sollten in einem vernünftigen APplikationsdesign sicherlich
eingang finden und sind wichtig für die User-Experience beim Erleben der Anwendung.
Im Android kann eine Applikation ja auch jederzeit vom System beendet werden, wenn
der Speicherplatz ausgeht. Um so wichtiger ist das also.

Beende ich meinen Applikationstask, und kümmere mich um korrekte Rückgabewerte,
dann beende ich wirklich nur meinen eigenen Kontext. Das andere muss die aufrufende
App. erledigen. Hier muss der onResume Zweig korrekt implementiert sein.

Beende ich eine Applikation mit finish() wird ja das Activity Result vom System
automatisch an ggf. meine Activity aufrufende Intents an den onActivityResult Handler
zurückpropagiert. Hierfür gibt es auch die Methode setResult() die eben diese Parameter
setzt.

Alles in allem denke ich und weiss aus Beruflicher Erfahrung, dass Applikationsdesign
kein einfaches Geschäft ist und sich hinter einer vermeintlich einfachen Anwendung
viele Detailfragen verbergen, die zunächst oft ausser Acht gelassen werden und erst
viel zu spät im Entwicklungsprozess aufpoppen. Dann ist es jedoch oft aus Kostengründen
kaum noch möglich, dass App. Design noch auf die richtige Schiene zu bringen und man
beginnt sich mit Workarounds zu behelfen, die einem das Leben richtig schwer machen
und der Experience der Applikation nicht wirklich förderlich sind.

Ich hab ja auch geschrieben, dass dieser öffnende Thread erst der Anfang wäre. Ich denke
dass wir gerade mit kritischen Anmerkungen wie jetzt von Dir, oder wie von MacSystems
alle gemeinsam die Möglichkeit haben viel voneinander zu lernen und unserer Erfahrungen
und bereits erlebten Fussfallen auszutauschen.

Ich für meinen Teil finde es jedenfalls ungemein hilfreich mit Euch über diese Dinge
diskutieren zu können und sich auszutauschen.

lg
Voss

lg Voss

Antworten
  • Forum-Beiträge: 1.727

24.06.2009 10:18:50 via Website

Hoffen wir das beste, bis jetzt sieht der Lifecyle überschaubar aus. Zumindest muss Ich nichts eigenes erfinden.
Heute steht mein erster Service für meine kleine Applikation an, nachdem Ich gestern das Parcelable verstanden habe kann es weiter gehen.

— geändert am 24.06.2009 10:23:11

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Gelöschter Account
  • Forum-Beiträge: 87

24.06.2009 22:24:15 via Website

Ich hab ja auch geschrieben, dass dieser öffnende Thread erst der Anfang wäre. Ich denke
dass wir gerade mit kritischen Anmerkungen wie jetzt von Dir, oder wie von MacSystems
alle gemeinsam die Möglichkeit haben viel voneinander zu lernen und unserer Erfahrungen
und bereits erlebten Fussfallen auszutauschen.


genauer deiner Meinung Jörg!

Antworten
Gelöschter Account
  • Forum-Beiträge: 5.136

24.06.2009 22:56:12 via Website

:grin: *Handschüttel*

lg Voss

Antworten
  • Forum-Beiträge: 2.644

26.06.2009 12:21:18 via Website

hab nochmal ein wenig drüber nachgedacht.

bei den von google bereitgestellten offizellen apps, gibts nirgends eine möglichkeit die app zu beenden. die werdens ja am besten wissen

swordiApps Blog - Website

Antworten
  • Forum-Beiträge: 1.614

27.06.2009 20:40:08 via Website

Markus Gursch
hab nochmal ein wenig drüber nachgedacht.

bei den von google bereitgestellten offizellen apps, gibts nirgends eine möglichkeit die app zu beenden. die werdens ja am besten wissen

Ob das aber richtig ist, ist wieder eine andere Frage.

Am liebsten wäre mir ja eine Art Taskleiste, die immer im Sichtfeld ist und mir zeigt, welche Apps gerade noch im Background laufen. Ein Widget auf dem Homescreen für den Task Manager Lite wäre ideal, finde ich.

Neu bei Android, AndroidPIT oder dem App Center? Hier erfährst Du alles Wichtige: http://bit.ly/ccFQvI

Antworten
  • Forum-Beiträge: 2.644

27.06.2009 23:43:20 via Website

hehe naja überleg mal

das betriebssystem kommt hauptsächlich von google ( auch wenn da andere dabei sind. google ist da sicher die stärkste macht )

die programme kommen von google

also ich würd sagen eher machen die es richtig, als irgendein lustiger kleiner programmierer vom berg

swordiApps Blog - Website

Antworten