В Activity <App Name> произошла утечка ServiceConnection <ServiceConnection Name> @ 438030a8, которая изначально была связана здесь


134

Я работаю над своим первым приложением для 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.onCreate ()? (com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onCreate (LightfactoryRemote.java:97))
tbruyelle 03

Ответы:


57

Вы не предоставили никакого кода 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);

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


Я запускаю службу с помощью START_STICKY, и она также запускается намерением загрузки. Если я вызываю StartService, он создает еще один экземпляр службы, и я не хочу, чтобы две службы работали одновременно. Как исправить ошибку в этом случае?
opc0de

16
@ opc0de, нет, вы не создаете другую службу, когда дважды вызываете startService (). Логически сервисы по своей природе являются одиночными. Независимо от того, сколько раз вы его запускаете, работает только одна служба.
mahkie

2
Какое решение для продолжения работы в фоновом режиме для музыкального плеера?
Ананд Савджани


31

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


13

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

Смотрите здесь .

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


7
как вы, возможно, уже заметили, наDestroy практически никогда не вызывается из операционной системы
martyglaubitz

См. Здесь ссылку для перехода к запрещенному контенту -> Предупреждение о запрещенном контенте. Кто-нибудь может получить доступ? Кнопка «Продолжить группировку» просто обновляет страницу и показывает мне такое же предупреждение.
Blaze Gawlik

11

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

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


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

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

2

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


1

Вы можете просто управлять им с помощью логического значения, поэтому вы вызываете 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;
    }
};

0

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

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

 onPause(){
   unbindService(YOUR_SERVICE);
   super.onPause();
 }

0

Я совсем недавно читал об 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 .

Более подробно об этом читайте в блоге Эрика .

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


0

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

  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);
        }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.