web-dev-qa-db-ja.com

ServiceConnectionLeaked in Android

Androidでいくつかの基本的なデータベース操作を実行するためにサービスを使用しようとしていますが、何らかの理由でアクティビティにServiceConnectionエラーが発生しています。Logcatの完全な読み出しを底。

複数のアクティビティで同じサービスを使用する必要があるため、すべてのサービスタスクを処理するスーパークラスを作成しました。次のようになります。

private MyInterface child;

public void onCreate(Bundle savedInstanceState, MyInterface child){
    super.onCreate(savedInstanceState);

    doBindService();
}

public void onResume(){
    super.onResume();

    doBindService();
}

protected void onPause(){
    super.onPause();

    doUnbindService();
}

private boolean bound;
private boolean binding;

ServiceConnection Connection = new ServiceConnection(){

    //called when the service is connected
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d(LOGTAG, "Bound to Service");
        bound = true;
        binding = false;
        toServiceMessenger = new Messenger(service);
        while(!commandsForService.isEmpty()){
            sendToService(commandsForService.poll());
        }
    }

    //called when the service is disconnected
    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.d(LOGTAG, "Unboud from Service");
        bound = false;
        binding = false;
        toServiceMessenger = null;
    }
};

private boolean doBindService(){
    Log.d(LOGTAG, "Attempting to Bind to Service");
    if(!bound && !binding){
        binding = true;
        bindService(new Intent(this, global.FetchService.class), Connection, Context.BIND_AUTO_CREATE);
    }
    return bound;
}

private void doUnbindService(){
    Log.d(LOGTAG, "Attempting to Unbind from Service");
    if(bound && !binding){
        binding = true;
        unbindService(Connection);
    }
}

public void sendToService(Message msg){
    if(bound){
        sendMessageToService(msg);
    }
    else{
        commandsForService.add(msg);
    }
}

private void sendMessageToService(Message msg){
    if(bound){
        msg.replyTo = fromServiceMessenger;
        try {
            toServiceMessenger.send(msg);
        } catch (RemoteException e) {
            Log.d(LOGTAG, "RemoteException communicating with service");
        }
    }
    else{
        Log.d(LOGTAG, "Error: toServiceMessenger null while bound");
    }
}

アイデアは、子アクティビティがサービスに接続されているかどうかを心配する必要がないということです。スーパークラスはデータを取得してサービスに戻し、子に戻す必要があります。

Logcatは、onCreate()のdoBindService()をポイントします-> bindService(new Intent(this、global.FetchService.class)、Connection、Context.BIND_AUTO_CREATE);エラーの原因となった行として。ただし、サービスがリークするのは、アクティビティが実行されてから15秒以上表示された後であるため、onCreate()が呼び出されているとは思いません。

ここにLogcatがあります:

09-02 09:25:40.635: E/ActivityThread(5963): Activity childActivity has leaked ServiceConnection superClass$1@42cb1b70 that was originally bound here
09-02 09:25:40.635: E/ActivityThread(5963): Android.app.ServiceConnectionLeaked: Activity childActivity has leaked ServiceConnection superClass$1@42cb1b70 that was originally bound here
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.Java:1055)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.LoadedApk.getServiceDispatcher(LoadedApk.Java:949)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.ContextImpl.bindService(ContextImpl.Java:1472)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.ContextImpl.bindService(ContextImpl.Java:1464)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.content.ContextWrapper.bindService(ContextWrapper.Java:394)
09-02 09:25:40.635: E/ActivityThread(5963):     at superClass.doBindService(FetchActivity.Java:253)
09-02 09:25:40.635: E/ActivityThread(5963):     at superClass.onCreate(FetchActivity.Java:61)
09-02 09:25:40.635: E/ActivityThread(5963):     at childActivity.onCreate(Showcase_Activity.Java:37)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.Activity.performCreate(Activity.Java:5066)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.Instrumentation.callActivityOnCreate(Instrumentation.Java:1101)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:2311)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:2391)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.ActivityThread.access$600(ActivityThread.Java:151)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1335)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.os.Handler.dispatchMessage(Handler.Java:99)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.os.Looper.loop(Looper.Java:155)
09-02 09:25:40.635: E/ActivityThread(5963):     at Android.app.ActivityThread.main(ActivityThread.Java:5493)
09-02 09:25:40.635: E/ActivityThread(5963):     at Java.lang.reflect.Method.invokeNative(Native Method)
09-02 09:25:40.635: E/ActivityThread(5963):     at Java.lang.reflect.Method.invoke(Method.Java:511)
09-02 09:25:40.635: E/ActivityThread(5963):     at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:1028)
09-02 09:25:40.635: E/ActivityThread(5963):     at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:795)
09-02 09:25:40.635: E/ActivityThread(5963):     at dalvik.system.NativeStart.main(Native Method)

どんな助けでも大歓迎です。

19
MrMannWood

doBindService()onCreate()を呼び出すときは、UnbindService()にdo onDestroy()を追加する必要があります。

わたしにはできる。

17
BinqiangSun

doBindService()onCreate()の両方でonResume()を呼び出しており、onResume()だけで呼び出してdoUnbindService() in onPause()

4
bclymer

あなたはActivity getActivity()が現在のものを返すための適切な参照を使用する必要があり、あなたはバインドしたものでバインドを解除する必要があります

これが私が問題を修正した方法です:

private Activity mActivity;
    @Override
    public void onStart() {
        super.onStart();
        if (!mBound) {
            startService();
            mActivity = getActivity();
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        if (mBound && mActivity != null) {
            mActivity.unbindService(mServiceConnection);
            mActivity = null;
        }
    }
1
Dounaka

アクティビティにバインドしたサービスは、そのアクティビティが破棄されても停止しないため、このエラーが発生します。そのため、このため、サービスはまだメモリ内に存在し、リソースを消費していますが、何もしていません。

この問題を解決するには、doBindService()onCreate()を呼び出し、doUnbindService()onDestroy()を呼び出します。

1
Vijay Vankhede

この問題はAndroid以前のSDKAndroid OAPIレベル26Android Oフォアグラウンドサービスを起動する次の関数が導入されました ContextCompat.startForegroundService(...)context.startService(...)とは対照的です。古いAPIはフォアグラウンドライフサイクルを処理しないため、context?.unbindService(serviceConnection)onDestroy(...)を呼び出す必要があります。

新しいメソッドにより、開発者はstartForeground(notificationId, notification)を呼び出してから5秒以内にContextCompat.startForegroundService(...)で通知を作成し、アプリが表示されていない場合でもフォアグラウンドサービスが実行されていることをユーザーに確実に知らせる必要があります。 。

NougatAPIレベル25以下を実行しているデバイスの場合は、サービスを手動でバインド解除してください。

ie

override fun onDestroy() {
    if (Android.os.Build.VERSION.SDK_INT <= Android.os.Build.VERSION_CODES.N_MR1) 
        context?.unbindService(serviceConnection)
}
0
Adam Hurwitz