<App Name> 활동이 원래 여기에 바인딩 된 ServiceConnection <ServiceConnection Name> @ 438030a8을 유출했습니다.


134

첫 번째 Android 앱을 개발 중입니다. 내 앱에 세 가지 활동이 있으며 사용자는 자주 자주 전환합니다. 또한 텔넷 연결을 처리하는 원격 서비스가 있습니다. 텔넷 메시지를 보내거나 받으려면 앱이이 서비스에 바인딩해야합니다.

편집은 당신이 당신의 정보 대답을 BDLS 감사드립니다. bindService()독립형 함수 또는 after로사용하는 것의 차이점에 대한 명확한 설명을 위해 코드를 다시 작성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()

따라서 활동이 시작되면 서비스가 시작되고 텔넷 연결에 성공하지 못한 경우 활동이 제거되면 중지됩니다 ( 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


당신의 제안을 위해 2nd Thanks bdls를 다시 한번 편집하십시오 . 나는 당신이 제안한대로onUnBind()서비스에 재정의를추가했습니다. onUnBind()실제로 모든 클라이언트가 서비스에서 연결을 끊을 때만 트리거되지만 홈 버튼을 누르면 실행되고 오류 메시지가 나타납니다! 모든 클라이언트가 서비스에서 바인딩 해제 되었기 때문에 이것이 나에게 이해가되지 않습니다. 확인 해봐:

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이 누출되면 그 후에 다시 연결을 수행합니다.

다른 하나는 개발자 도구에서 "활동 즉시 파괴"를 설정하면이 오류를 방지합니다.

어떤 아이디어?


LightfactoryRemote.onCreate () 코드를 추가 할 수 있습니까? (com.wingedvictorydesign.LightfactoryRemote.LightfactoryRemote.onCreate (LightfactoryRemote.java:97))
tbruyelle

답변:


57

에서 코드를 제공하지 않았 LightFactoryRemote으므로 이것은 추정 일 뿐이지 만 bindService메소드를 자체적 으로 사용하는 경우 나타나는 일종의 문제처럼 보입니다 .

서비스를 시작한 활동에 onDestroy메소드를 호출 한 후에도 서비스가 계속 실행되도록하려면 먼저을 사용해야 startService합니다.

startService 상태에 대한 Android 문서 :

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를 호출하면 다른 서비스 인스턴스가 생성되고 동시에 2 개의 서비스가 실행되는 것을 원하지 않습니다. 이 경우 오류를 어떻게 해결할 수 있습니까?
opc0de

16
@ opc0de, no startService ()를 두 번 호출 할 때 다른 서비스를 작성하지 않습니다. 서비스는 본질적으로 논리적으로 싱글 톤입니다. 시작 횟수에 관계없이 하나의 서비스 만 실행됩니다.
mahkie

2
음악 플레이어를위한 백그라운드에서 서비스를 계속하기위한 솔루션은 무엇입니까?
Anand Savjani


31

에 바인딩 onResume하지만 바인딩을 해제 onDestroy합니다. onPause바인드 / 바인드 해제 호출이 항상 일치하도록 바인드를 대신 해제해야 합니다. 간헐적 인 오류는 활동이 일시 중지되었지만 파괴되지 않은 다음 다시 시작되는 위치입니다.


13

의 서비스를 바인딩 해제하면됩니다 onDestroy(). 그러면 경고가납니다.

여기를 참조 하십시오 .

활동 문서가 설명하려고 할 때 사용할 세 가지 주요 바인드 / 바인드 해제 그룹이 있습니다 : onCreate () 및 onDestroy (), onStart () 및 onStop (), onResume () 및 onPause ().


7
당신이 eyperienced했을 수도 있듯이 파괴 는 운영 체제에서 거의 호출 되지 않습니다
martyglaubitz

금지 된 콘텐츠-> 금지 된 콘텐츠 경고로 전달되는 링크를 참조하십시오. 누구나 접근 할 수 있습니까? "Continue to Group"버튼은 페이지를 새로 고침하고 동일한 경고를 표시합니다.
Blaze Gawlik 2016 년

11

사용자가 활동을 매우 빠르게 전환한다고 언급했습니다. unbindService서비스 연결이 설정되기 전에 전화 한 것일 수 있습니까? 이것은 바인딩 해제에 실패한 다음 바인딩을 누출시키는 효과가 있습니다.

당신이 이것을 어떻게 다룰 수 있는지 완전히 모릅니다 ... 아마도 onServiceConnected전화가 왔을 때 이미 전화를 받았다 unbindService면 전화 할 수 onDestroy있습니다. 그래도 작동하는지 확실하지 않습니다.


아직 서비스에 onUnbind 메소드를 추가 할 수 없습니다. 이렇게하면 클래스가 바인딩 해제 된 시점을 정확하게 볼 수 있으며 디버깅에 도움이 될 수 있습니다.

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

2

OnUserLeaveHint ()에서 unbindService ()를 사용해보십시오. ServiceConnection 누수 시나리오 및 기타 예외를 방지합니다.
내 코드에서 사용하고 정상적으로 작동합니다.


1

부울로 제어 할 수 있으므로 바인드가 수행 된 경우에만 바인딩 해제를 호출합니다.

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 서비스에 대해 읽었으며 그것에 대해 깊이 배울 수있는 기회를 얻었습니다. 나는 내가했기 때문에이 일이 내 상황에 대한 서비스 누수가 발생했을 언 바운드 시작되었다 서비스 바운드 서비스를하지만,이 내 언 바운드 서비스는로 대체 활동 .

따라서 stopSelf () 를 사용하여 바인딩되지 않은 서비스를 중지 할 때 누수가 발생했기 때문에 바인딩 된 서비스를 바인딩 해제하지 않고 부모 서비스 를 중지했기 때문 입니다. 이제 바운드 서비스가 실행 중이며 누가 속한 사람인지 모릅니다.

쉽고 간단한 해결책은 unbindService (YOUR_SERVICE); 부모 활동 / 서비스 의 onDestroy () 함수에서. 이렇게하면 라이프 사이클에서 상위 활동 / 서비스가 다운되기 전에 바인딩 된 서비스가 중지되거나 정리됩니다.

이 문제의 다른 변형이 있습니다. 때로는 바인딩 서비스에서 서비스가 바인딩 된 경우에만 특정 함수가 작동하기를 원하므로 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.

이 내용은 Erik의 블로그 에서 자세히 다룹니다 .

여기 온 사람이 그의 호기심을 만족 시키길 바랍니다


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. 서비스 바인딩 해제

        if (serviceBound) {
            unbindService(serviceConnection);
        }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.