Я работаю над своим первым приложением для Android. В моем приложении есть три действия, и пользователь довольно часто переключается туда и обратно. У меня также есть удаленная служба, которая обрабатывает telnet-соединение. Приложения должны быть привязаны к этой службе, чтобы отправлять / получать сообщения telnet.
Edit
Спасибо BDLS за информативный ответ. Я переписал свой код в свете вашего разъяснения разницы между использованиемbindService()
в качестве автономной функции или послеstartService()
, и теперь я получаю сообщение об ошибке утечки только периодически, когда использую кнопку возврата для переключения между действиями.
Моя активность подключения имеет следующее onCreate()
и 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()
Таким образом, служба запускается при запуске действия и останавливается, когда действие уничтожается, если не было установлено успешное соединение telnet ( connectStatus == 0
). Другие действия привязываются к службе, только если было установлено успешное соединение ( connectStatus == 1
сохранено в общих настройках). Вот их onResume()
и 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()
Таким образом, привязка происходит onResume()
таким образом, что она подбирает измененное состояние из активности соединения, а в onDestroy()
функции оно не привязано, если необходимо.
Конец Править
Но я по-прежнему получаю сообщение об ошибке утечки памяти «Утечка активности ServiceConnection @ 438030a8, которая изначально была привязана здесь» при переключении действий. Что я делаю не так?
Заранее благодарим за любые советы или указатели !!!
Полное сообщение об ошибке следует (из исправленного кода):
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
Редактировать 2-е.
Еще раз спасибо bdls за ваши предложения. Я сделал, как вы предложили, и добавилonUnBind()
в службу переопределение. onUnBind()
на самом деле срабатывает только тогда, когда все клиенты отключаются от службы, но когда я нажимаю кнопку домой, он запускается, а затем появляется сообщение об ошибке! Для меня это не имеет смысла, поскольку все клиенты не связаны с сервисом, так как же один уничтоженный мог утечь serviceConnection? Проверьте это:
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
Я подумал, что это может быть что-то вроде того, что вы сказали, когда привязка к службе не завершена при unbindService()
вызове, однако я попытался вызвать метод службы, поскольку я поддерживал каждое действие, чтобы убедиться, что привязка завершена, и все они пошли через штраф.
В общем, такое поведение не связано с тем, как долго я занимаюсь каждым видом деятельности. Однако, как только первое действие пропускает свой serviceConnection, все они делают то же, что и я, после этого.
Еще одна вещь: если я включу «Немедленное уничтожение действий» в Dev Tools, это предотвратит эту ошибку.
Любые идеи?
источник
Ответы:
Вы не предоставили никакого кода
LightFactoryRemote
, так что это только предположение, но похоже, что вы столкнулись бы с той проблемой, которая возникла бы, если бы вы использовалиbindService
метод сам по себе.Чтобы служба продолжала работать, даже после того, как у запущенного действия был
onDestroy
вызван метод, вы должны сначала использоватьstartService
.Документы Android для состояния startService :
В то время как для bindService :
Итак, произошло то, что действие, связавшее (и, следовательно, запустившее) службу, было остановлено, и поэтому система считает, что служба больше не требуется, и вызывает эту ошибку (а затем, вероятно, останавливает службу).
пример
В этом примере службу следует продолжать работать независимо от того, выполняется ли вызывающая активность.
Первая строка запускает службу, а вторая связывает ее с действием.
источник
Ты можешь использовать:
источник
Вы связываете,
onResume
но развязываетеonDestroy
.onPause
Вместо этого вы должны выполнить отмену привязки, чтобы всегда были совпадающие пары вызовов привязки / отмены привязки. Ваши периодические ошибки будут связаны с тем, что ваша деятельность будет приостановлена, но не уничтожена, а затем возобновлена снова.источник
Вам нужно только отвязать сервис в
onDestroy()
. Затем появится предупреждение.Смотрите здесь .
источник
Вы упомянули, что пользователь довольно быстро переключается между Activity. Может быть, вы звоните
unbindService
до того, как будет установлено сервисное соединение? Это может привести к невозможности отвязки, а затем к утечке привязки.Не совсем уверен, как вы могли бы справиться с этим ... Возможно, когда
onServiceConnected
вызывается, вы могли бы позвонить,unbindService
еслиonDestroy
он уже был вызван. Не уверен, что это сработает.Если вы еще этого не сделали, вы можете добавить к своей службе метод onUnbind. Таким образом, вы можете точно увидеть, когда ваши классы отвязаны от него, и это может помочь с отладкой.
источник
Попробуйте использовать unbindService () в OnUserLeaveHint (). Это предотвращает сценарий утечки ServiceConnection и другие исключения.
Я использовал его в своем коде и отлично работает.
источник
Вы можете просто управлять им с помощью логического значения, поэтому вы вызываете unbind только в том случае, если привязка была сделана
Если вы хотите отвязать его, только если он был подключен
источник
Каждая служба, связанная с активностью, должна быть отменена при закрытии приложения.
Так что попробуйте использовать
источник
Я совсем недавно читал об Android Service и получил возможность глубоко погрузиться в него. Я обнаружил утечку службы, для моей ситуации это произошло потому , что я имел несвязанную службу , который , начиная с связанной службой, но в этом моя несвязанной службе заменяется деятельность .
Итак, когда я останавливал свою несвязанную службу с помощью stopSelf (), произошла утечка, причина заключалась в том, что я останавливал родительскую службу без отмены привязки связанной службы. Теперь связанная служба запущена и не знает, кому она принадлежит.
Простое и понятное решение - вызвать unbindService (YOUR_SERVICE); в вашей функции onDestroy () родительского Activity / Service. Таким образом, жизненный цикл гарантирует, что ваши связанные службы будут остановлены или очищены до того, как ваша родительская Activity / Services отключится.
Есть еще один вариант этой проблемы. Иногда в вашей связанной службе вы хотите, чтобы определенные функции работали только в том случае, если служба привязана, поэтому мы в конечном итоге помещаем связанный флаг в onServiceConnected, например:
Это работает до сих пор, но проблема возникает, когда мы рассматриваем функцию onServiceDisconnected как обратный вызов для вызова функции unbindService , это по документации вызывается только тогда, когда служба убита или аварийно завершена . И вы никогда не получите этот обратный вызов в том же потоке . Следовательно, мы делаем что-то вроде:
Это создает серьезную ошибку в коде, потому что наш связанный флаг никогда не сбрасывается в false, и когда эта служба снова подключается снова, в большинстве случаев это так
true
. Поэтому, чтобы избежать этого сценария, вы должны установитьbound
значение false в момент, когда вы звонитеunbindService
.Более подробно об этом читайте в блоге Эрика .
Всякая надежда, приходившая сюда, удовлетворила его любопытство.
источник
эта ошибка возникает, когда вы собираетесь привязать ограниченную службу. Итак, соль должна быть: -
в сервисном соединении добавьте serviceBound, как показано ниже:
};
отвязать услугу onDestroy
источник