Действие ‹Имя приложения› утечка ServiceConnection ‹Имя ServiceConnection› @ 438030a8, которое изначально было привязано сюда

Я работаю над своим первым приложением для Android. В моем приложении есть три действия, и пользователь довольно часто переключается туда и обратно. У меня также есть удаленная служба, которая обрабатывает telnet-соединение. Приложения должны быть привязаны к этой службе, чтобы отправлять / получать сообщения telnet.

Редактировать Спасибо, 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

Редактировать вторую
Еще раз спасибо, 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, это предотвратит эту ошибку.

Любые идеи?


person catdotgif    schedule 02.01.2010    source источник
comment
Можете ли вы добавить код LightfactoryRemote.onCreate ()? (com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onCreate (LightfactoryRemote.java:97))   -  person tbruyelle    schedule 03.01.2010


Ответы (10)


Вы не предоставили никакого кода из LightFactoryRemote, так что это только предположение, но похоже на проблему, которую вы бы увидели, если бы использовали метод bindService сам по себе.

Чтобы служба продолжала работать, даже после того, как у запущенного действия был вызван onDestroy метод, сначала следует использовать startService.

Документы Android для startService штат:

Использование startService () переопределяет время жизни службы по умолчанию, которым управляет bindService (Intent, ServiceConnection, int): это требует, чтобы служба продолжала работать до вызова stopService (Intent), независимо от того, подключены ли к ней какие-либо клиенты.

Тогда как для bindService:

Услуга будет считаться необходимой системой только до тех пор, пока существует вызывающий контекст. Например, если этот контекст является остановленным действием, от службы не потребуется продолжать работу, пока действие не будет возобновлено.


Итак, что произошло, так это то, что действие, которое связывало (и, следовательно, запускало) службу, было остановлено, и, таким образом, система считает, что служба больше не требуется, и вызывает эту ошибку (а затем, вероятно, останавливает службу).


Пример

В этом примере службу следует продолжать работать независимо от того, выполняется ли вызывающая активность.

ComponentName myService = startService(new Intent(this, myClass.class));
bindService(new Intent(this, myClass.class), myServiceConn, BIND_AUTO_CREATE);

Первая строка запускает службу, а вторая связывает ее с действием.

person bdls    schedule 03.01.2010
comment
Я запускаю службу с помощью START_STICKY, и она также запускается намерением загрузки. Если я вызываю StartService, он создает еще один экземпляр службы, и я не хочу, чтобы две службы работали одновременно. Как исправить ошибку в этом случае? - person opc0de; 10.10.2012
comment
@ opc0de, нет, вы не создаете другую службу, когда дважды вызываете startService (). Логически сервисы по своей природе являются одиночными. Независимо от того, сколько раз вы его запускаете, работает только одна служба. - person mahkie; 14.03.2013
comment
Какое решение для продолжения службы в фоновом режиме для музыкального плеера? - person Anand Savjani; 25.11.2016

Вы можете использовать:

@Override
public void onDestroy() {
    super.onDestroy();

    if (mServiceConn != null) {
        unbindService(mServiceConn);
    }
}
person Mostafa Rostami    schedule 25.04.2014
comment
Превосходно. Это и есть. - person Seltsam; 05.04.2020

Вы выполняете привязку onResume, но отменяете привязку onDestroy. Вместо этого вы должны выполнить отмену привязки в onPause, чтобы всегда были совпадающие пары вызовов привязки / отмены привязки. Ваши периодические ошибки будут связаны с тем, что ваша деятельность будет приостановлена, но не уничтожена, а затем возобновлена ​​снова.

person Nick    schedule 06.11.2010

Вам нужно только отвязать службу в onDestroy(). Затем появится предупреждение.

См. здесь.

Как пытается объяснить документ Activity, вы будете использовать три основных группировки привязки / отмены: onCreate () и onDestroy (), onStart () и onStop (), а также onResume () и onPause ().

person pierrotlefou    schedule 20.07.2011
comment
как вы могли заметить, onDestroy практически никогда не вызывается из операционной системы - person martyglaubitz; 12.11.2012
comment
См. Здесь ссылку для перехода к запрещенному контенту - ›Предупреждение о запрещенном контенте. Кто-нибудь может получить доступ? Кнопка «Продолжить группировку» просто обновляет страницу и показывает то же предупреждение для меня. - person Blaze Gawlik; 13.06.2018

Вы упомянули, что пользователь довольно быстро переключается между Activity. Может быть, вы звоните unbindService до того, как будет установлено соединение со службой? Это может привести к невозможности отвязки, а затем к утечке привязки.

Не совсем уверен, как вы могли бы справиться с этим ... Возможно, когда вызывается onServiceConnected, вы могли бы вызвать unbindService, если onDestroy уже был вызван. Не уверен, что это сработает.


Если вы еще этого не сделали, вы можете добавить к своей службе метод onUnbind. Таким образом, вы можете точно увидеть, когда ваши классы отвязаны от него, и это может помочь при отладке.

@Override
public boolean onUnbind(Intent intent) {
    Log.d(this.getClass().getName(), "UNBIND");
    return true;
}
person bdls    schedule 03.01.2010

Попробуйте использовать unbindService () в OnUserLeaveHint (). Это предотвращает сценарий утечки ServiceConnection и другие исключения.
Я использовал его в своем коде и отлично работает.

person Ashwini Shahapurkar    schedule 04.01.2011

эта ошибка возникает, когда вы собираетесь привязать ограниченную службу. Итак, соль должна быть: -

  1. в сервисном соединении добавьте serviceBound, как показано ниже:

    private final ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // your work here.
    
        serviceBound = true;
    
    }
    
    @Override
    public void onServiceDisconnected(ComponentName name) {
    
        serviceBound = false;
    }
    

    };

  2. отвязать услугу onDestroy

        if (serviceBound) {
            unbindService(serviceConnection);
        }
    
person Atef Farouk    schedule 20.07.2020

Вы можете просто управлять им с помощью логического значения, поэтому вы вызываете unbind только в том случае, если привязка была сделана

public void doBindService()
{
    if (!mIsBound)
    {
        bindService(new Intent(this, DMusic.class), Scon, Context.BIND_AUTO_CREATE);
        mIsBound = true;
    }
}

public void doUnbindService()
{
    if (mIsBound)
    {
        unbindService(Scon);
        mIsBound = false;
    }
}

Если вы хотите отвязать его только в том случае, если он был подключен

public ServiceConnection Scon = new ServiceConnection() {

    public void onServiceConnected(ComponentName name, IBinder binder)
    {
        mServ = ((DMusic.ServiceBinder) binder).getService();
        mIsBound = true;
    }

    public void onServiceDisconnected(ComponentName name)
    {
        mServ = null;
    }
};
person D4rWiNS    schedule 03.11.2014

Каждая служба, связанная с активностью, должна быть отменена при закрытии приложения.

Так что попробуйте использовать

 onPause(){
   unbindService(YOUR_SERVICE);
   super.onPause();
 }
person Punit    schedule 27.03.2014

Я совсем недавно читал об Android Service и получил возможность глубоко погрузиться в него. Я столкнулся с утечкой службы, в моей ситуации это произошло из-за того, что у меня была несвязанная служба, которая запускала связанную службу, но в этом моем несвязанном Служба заменяется Действие.

Итак, когда я останавливал свою несвязанную службу с помощью stopSelf (), произошла утечка, причина заключалась в том, что я останавливал родительскую службу без отмены привязки связанной службы. Теперь связанная служба запущена и не знает, кому она принадлежит.

Простое и прямое решение - вы должны вызвать unbindService (YOUR_SERVICE); в функции onDestroy () родительского Activity / Service. Таким образом, жизненный цикл гарантирует, что ваши связанные службы будут остановлены или очищены до того, как родительские Activity / Services отключатся.

Есть еще один вариант этой проблемы. Иногда в вашей связанной службе вы хотите, чтобы определенные функции работали только в том случае, если служба связана, поэтому мы в конечном итоге помещаем связанный флаг в onServiceConnected, например:

public void onServiceConnected(ComponentName name, IBinder service) {
            bounded = true;
            // code here
        }

До сих пор это работает нормально, но проблема возникает, когда мы обрабатываем onServiceDisconnected в качестве обратного вызова для вызова функции unbindService. Документация требует, чтобы эта функция вызывалась только тогда, когда служба отключена или аварийно завершена. И вы никогда не получите этот обратный вызов в той же цепочке. Следовательно, мы делаем что-то вроде:

public void onServiceDisconnected(ComponentName name) {
            bounded = false;
        }

Это создает серьезную ошибку в коде, потому что наш связанный флаг никогда не сбрасывается в значение false, а когда эта служба снова подключается снова, в большинстве случаев это true. Поэтому, чтобы избежать этого сценария, вы должны установить для bound значение false в тот момент, когда вы вызываете unbindService.

Подробнее об этом можно прочитать в блоге Эрика .

Всякая надежда, приходившая сюда, удовлетворила его любопытство.

person Farhaan Bukhsh    schedule 06.06.2020