Ich arbeite an meiner ersten Android App. Ich habe drei Aktivitäten in meiner App und der Benutzer wechselt ziemlich häufig hin und her. Ich habe auch einen Remote-Dienst, der eine Telnet-Verbindung verwaltet. Die Apps müssen sich an diesen Dienst binden, um Telnet-Nachrichten senden / empfangen zu können.
Bearbeiten
Vielen Dank an BDLS für Ihre informative Antwort. Ich habe meinen Code im Lichte Ihrer Klarstellung über den Unterschied zwischen der VerwendungbindService()
als eigenständige Funktion oder danach neu geschriebenstartService()
und erhalte jetzt nur zeitweise die Leckfehlermeldung, wenn Sie die Zurück-Taste zum Wechseln zwischen Aktivitäten verwenden.
Meine Verbindungsaktivität hat Folgendes onCreate()
und onDestroy()
:
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
* Initialize the ServiceConnection. Note that this is the only place startService() is run.
* It is also the only time bindService is run without dependency on connectStatus.
*/
conn = new TelnetServiceConnection();
//start the service which handles telnet
Intent i = new Intent();
i.setClassName( "com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService" );
startService(i);
//bind to the service
bindService(i, conn, 0);
setContentView(R.layout.connect);
setupConnectUI();
}//end OnCreate()
@Override
protected void onDestroy() {
super.onDestroy();
//unbind the service and null it out
if (conn != null) {
unbindService(conn);
conn = null;
}
if(connectStatus == 0) {
//stop the service
Intent i = new Intent();
i.setClassName( "com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService" );
stopService(i);
Log.d("LightfactoryRemote", "Connect onDestroy() attempted to stop service");
}
Log.d("LightfactoryRemote", "Connect onDestroy()");
}//end onDestroy()
Der Dienst wird also gestartet, wenn die Aktivität gestartet wird, und gestoppt, wenn die Aktivität zerstört wird, wenn keine erfolgreiche Telnet-Verbindung hergestellt wurde ( connectStatus == 0
). Die anderen Aktivitäten sind nur dann an den Dienst gebunden, wenn eine erfolgreiche Verbindung hergestellt wurde ( connectStatus == 1
gespeichert in gemeinsamen Einstellungen). Hier ist ihr onResume()
und onDestroy()
:
@Override
protected void onResume() {
super.onResume();
//retrieve the shared preferences file, and grab the connectionStatus out of it.
SharedPreferences settings = getSharedPreferences(PREFS_NAME, MODE_WORLD_WRITEABLE);
connectStatus = settings.getInt("connectStatus", 0);
Log.d("LightfactoryRemote", "Focus onResume with " + connectStatus);
//if a telnet connection is active, start the service and bind to it
if (connectStatus == 1) {
conn = new TelnetServiceConnection();
Intent i = new Intent();
i.setClassName("com.wingedvictorydesign.LightfactoryRemote", "com.wingedvictorydesign.LightfactoryRemote.TelnetService");
bindService(i, conn, 0);
//TODO write restore texview code
}//end if
}//end onResume
@Override
protected void onDestroy() {
super.onDestroy();
//unbind the service and null it out.
if (conn != null) {
Log.d("LightfactoryRemote", "Focus onDestroy() attempted to unbind service");
unbindService(conn);
conn = null;
}
Log.d("LightfactoryRemote", "Focus onDestroy()");
}//end onDestroy()
Die Bindung erfolgt also onResume()
so, dass der geänderte Status aus der Verbindungsaktivität übernommen wird, und in der onDestroy()
Funktion ist sie gegebenenfalls ungebunden.
Bearbeiten beenden
Ich erhalte jedoch immer noch die Fehlermeldung "Speicherverlust" "Aktivität hat ServiceConnection @ 438030a8 durchgesickert, die ursprünglich hier gebunden war", wenn zeitweise Aktivitäten gewechselt werden. Was mache ich falsch?
Vielen Dank im Voraus für alle Tipps oder Hinweise !!!
Es folgt die vollständige Fehlermeldung (aus dem überarbeiteten Code):
01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onStop()
01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onDestroy() attempted to unbind service
01-02 22:04:26.642: DEBUG/LightfactoryRemote(2024): Focus onDestroy()
01-02 22:04:26.672: ERROR/ActivityThread(2024): Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@439e51e8 that was originally bound here
01-02 22:04:26.672: ERROR/ActivityThread(2024): android.app.ServiceConnectionLeaked: Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@439e51e8 that was originally bound here
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:927)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:822)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.ApplicationContext.bindService(ApplicationContext.java:842)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.content.ContextWrapper.bindService(ContextWrapper.java:319)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onResume(LightfactoryRemote.java:102)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1225)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.Activity.performResume(Activity.java:3559)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2838)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2866)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2420)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.ActivityThread.access$2100(ActivityThread.java:116)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.os.Handler.dispatchMessage(Handler.java:99)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.os.Looper.loop(Looper.java:123)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at android.app.ActivityThread.main(ActivityThread.java:4203)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at java.lang.reflect.Method.invokeNative(Native Method)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at java.lang.reflect.Method.invoke(Method.java:521)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
01-02 22:04:26.672: ERROR/ActivityThread(2024): at dalvik.system.NativeStart.main(Native Method)
01-02 22:04:26.692: WARN/ActivityManager(558): Unbind failed: could not find connection for android.os.BinderProxy@43c509a8
Bearbeiten Sie die 2.
Danke noch einmal bdls für Ihre Vorschläge. Ich habe getan, was Sie vorgeschlagen haben, undonUnBind()
dem ServiceeineÜberschreibunghinzugefügt. onUnBind()
wird eigentlich nur ausgelöst, wenn alle Clients die Verbindung zum Dienst trennen, aber wenn ich die Home-Taste drücke, wird sie ausgeführt, und die Fehlermeldung wird angezeigt! Dies macht für mich keinen Sinn, da alle Clients nicht an den Service gebunden waren. Wie könnte der zerstörte also eine serviceConnection auslaufen lassen? Hör zu:
01-03 19:38:30.837: DEBUG/LightfactoryRemote(1118): Focus onPause()1
01-03 19:38:31.577: WARN/IInputConnectionWrapper(1118): showStatusIcon on inactive InputConnection
01-03 19:38:31.587: DEBUG/LightfactoryRemote(1118): Focus onStop()
01-03 19:38:31.600: DEBUG/LightfactoryRemote(1118): Focus onDestroy() attempted to unbind service
01-03 19:38:31.607: DEBUG/LightfactoryRemote(1118): Focus onDestroy()
01-03 19:38:31.677: DEBUG/LightfactoryRemote(1125): TelnetService onUnBind()
01-03 19:38:31.727: ERROR/ActivityThread(1118): Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@435baeb0 that was originally bound here
01-03 19:38:31.727: ERROR/ActivityThread(1118): android.app.ServiceConnectionLeaked: Activity com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote has leaked ServiceConnection com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote$TelnetServiceConnection@435baeb0 that was originally bound here
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:886)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:781)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.ApplicationContext.bindService(ApplicationContext.java:820)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.content.ContextWrapper.bindService(ContextWrapper.java:307)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onResume(LightfactoryRemote.java:102)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1225)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.Activity.performResume(Activity.java:3530)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2619)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2647)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2287)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.ActivityThread.access$1800(ActivityThread.java:112)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.os.Handler.dispatchMessage(Handler.java:99)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.os.Looper.loop(Looper.java:123)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at android.app.ActivityThread.main(ActivityThread.java:3948)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at java.lang.reflect.Method.invokeNative(Native Method)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at java.lang.reflect.Method.invoke(Method.java:521)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
01-03 19:38:31.727: ERROR/ActivityThread(1118): at dalvik.system.NativeStart.main(Native Method)
01-03 19:38:31.777: WARN/ActivityManager(564): Unbind failed: could not find connection for android.os.BinderProxy@4370f8a8
Ich dachte, es könnte so etwas wie das sein, was Sie gesagt haben, bei dem die Bindung an den Dienst nicht vollständig unbindService()
ist, wenn es aufgerufen wird. Ich habe jedoch versucht, eine Methode für den Dienst aufzurufen, während ich jede Aktivität durchgesehen habe, um zu überprüfen, ob die Bindung vollständig ist, und alle gingen durch gut.
Im Allgemeinen scheint dieses Verhalten nicht damit zu tun zu haben, wie lange ich in jeder Aktivität bleibe. Sobald die erste Aktivität ihre serviceConnection verliert, tun sie alle, was ich danach durch sie zurück gehe.
Eine andere Sache, wenn ich in Dev Tools "Aktivitäten sofort zerstören" aktiviere, wird dieser Fehler verhindert.
Irgendwelche Ideen?
quelle
Antworten:
Sie haben keinen Code von bereitgestellt
LightFactoryRemote
, daher ist dies nur eine Vermutung, aber es sieht nach dem Problem aus, das Sie sehen würden, wenn Sie diebindService
Methode alleine verwenden würden.Um sicherzustellen, dass ein Dienst auch nach dem Aufrufen der
onDestroy
Methode, die gestartet wurde, weiter ausgeführt wird , sollten Sie ihn zuerst verwendenstartService
.Die Android-Dokumente für den StartService- Status:
Für bindService gilt Folgendes :
Was also passiert ist, ist die Aktivität, die den Dienst gebunden (und daher gestartet) hat, gestoppt wurde, und daher glaubt das System, dass der Dienst nicht mehr benötigt wird, und verursacht diesen Fehler (und stoppt dann wahrscheinlich den Dienst).
Beispiel
In diesem Beispiel sollte der Dienst weiterhin ausgeführt werden, unabhängig davon, ob die aufrufende Aktivität ausgeführt wird.
Die erste Zeile startet den Dienst und die zweite bindet ihn an die Aktivität.
quelle
Sie können verwenden:
quelle
Sie binden sich ein
onResume
, lösen sich aber aufonDestroy
. Sie solltenonPause
stattdessen das Aufheben der Bindung durchführen, damit immer übereinstimmende Paare von Bindungs- / Entbindungsaufrufen vorhanden sind. Bei Ihren zeitweiligen Fehlern wird Ihre Aktivität angehalten, aber nicht zerstört und dann wieder aufgenommen.quelle
Sie sollten nur den Dienst in binden müssen
onDestroy()
. Dann geht die Warnung.Siehe hier .
quelle
Sie erwähnen, dass der Benutzer ziemlich schnell zwischen Aktivitäten wechselt. Könnte es sein, dass Sie anrufen,
unbindService
bevor die Dienstverbindung hergestellt wurde? Dies kann dazu führen, dass die Bindung nicht gelöst und die Bindung verloren geht.Nicht ganz sicher, wie Sie damit umgehen könnten ... Wenn
onServiceConnected
Sie angerufen werden, können Sie vielleicht anrufen,unbindService
wennonDestroy
bereits angerufen wurde. Ich bin mir nicht sicher, ob das funktionieren wird.Wenn Sie dies noch nicht getan haben, können Sie Ihrem Dienst eine onUnbind-Methode hinzufügen. Auf diese Weise können Sie genau sehen, wann sich Ihre Klassen davon lösen, und dies kann beim Debuggen hilfreich sein.
quelle
Versuchen Sie, unbindService () in OnUserLeaveHint () zu verwenden. Es verhindert das durchgesickerte ServiceConnection-Szenario und andere Ausnahmen.
Ich habe es in meinem Code verwendet und funktioniert gut.
quelle
Sie können es einfach mit einem Booleschen Wert steuern, sodass Sie Unbind nur aufrufen, wenn eine Bindung hergestellt wurde
Wenn Sie es nur lösen möchten, wenn es verbunden wurde
quelle
Jeder Dienst, der an Aktivitäten gebunden ist, muss beim Schließen der App aufgehoben werden.
Also versuchen Sie es mit
quelle
Ich habe vor kurzem über Android Service gelesen und hatte die Gelegenheit, mich eingehend damit zu beschäftigen. Ich bin auf ein Dienstleck gestoßen. In meiner Situation war dies darauf zurückzuführen, dass ich einen ungebundenen Dienst hatte, der einen gebundenen Dienst startete. In diesem Fall wird mein ungebundener Dienst durch eine Aktivität ersetzt .
Als ich meinen ungebundenen Dienst mithilfe von stopSelf () stoppte, trat das Leck auf. Der Grund dafür war, dass ich den übergeordneten Dienst stoppte , ohne den gebundenen Dienst zu lösen . Jetzt wird der gebundene Dienst ausgeführt und er weiß nicht, wem er gehört.
Die einfache und unkomplizierte Lösung besteht darin, dass Sie unbindService (YOUR_SERVICE) aufrufen sollten. in Ihrer onDestroy () -Funktion Ihrer übergeordneten Aktivität / Ihres übergeordneten Dienstes. Auf diese Weise stellt der Lebenszyklus sicher, dass Ihre gebundenen Dienste gestoppt oder bereinigt werden, bevor Ihre übergeordneten Aktivitäten / Dienste ausfallen.
Es gibt noch eine andere Variante dieses Problems. Manchmal möchten Sie, dass in Ihrem gebundenen Dienst bestimmte Funktionen nur funktionieren, wenn der Dienst gebunden ist, sodass wir am Ende ein gebundenes Flag in onServiceConnected setzen, wie:
Dies funktioniert bis hierher einwandfrei, aber das Problem tritt auf, wenn wir die Funktion onServiceDisconnected als Rückruf für den Funktionsaufruf unbindService behandeln. Dies wird laut Dokumentation nur aufgerufen, wenn ein Dienst beendet oder abgestürzt ist . Und Sie werden diesen Rückruf niemals im selben Thread erhalten . Daher machen wir am Ende so etwas wie:
Dies führt zu einem schwerwiegenden Fehler im Code, da unser gebundenes Flag niemals auf false zurückgesetzt wird und wenn dieser Dienst meistens wieder verbunden wird
true
. Um dieses Szenario zu vermeiden, sollten Sie denbound
Wert in dem Moment, in dem Sie anrufen, auf false setzenunbindService
.Dies wird ausführlicher in Eriks Blog behandelt .
Die Hoffnung, die jemals hierher gekommen ist, hat seine Neugier befriedigt.
quelle
Dieser Fehler tritt auf, wenn Sie einen begrenzten Dienst binden. Sol sollte also sein: -
Fügen Sie in der Serviceverbindung serviceBound wie folgt hinzu:
};
Service aufDestroy aufheben
quelle