android - 当 Activity 从最近的 Activity 中被刷掉时,优雅地清理绑定(bind)服务

标签 android android-activity android-service

我有一个绑定(bind)服务,它会在需要时转到前台。
这是我所拥有的简化版本:

class MyService extends Service {
    private static final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder serviceBinder) {
            instance.bound();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            instance.unbound();
        }
    };
    private static MyService instance;

    public MyService() {
        instance = this;
    }

    public static boolean bind(final Context context) {
        final Intent intent = new Intent(context, MyService.class);
        return context.bindService(intent, MyService.serviceConnection, Context.BIND_AUTO_CREATE);
    }

    public static void unbind(final Context context) {
        context.unbindService(MyService.serviceConnection);
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        // not being called
    }

    @Override
    public boolean onUnbind(Intent intent) {
        // not being called
    }

    private void bound() {}

    private void unbound() {
        // not being called
    }
}

然后在我的 Activity 中我只是这样做来绑定(bind):

MyService.bind(this);

这是解除绑定(bind):

MyService.unbind(this);

问题是我似乎无法知道用户何时关闭了最近的 Activity 。

这是我尝试过的:

  1. 使用 Activity onDestroy方法:不,没有被调用
  2. 使用 Activity onPause/onStop 方法:无法真正区分滑动情况和直接进入后台,因为 isFinishing() 在所有情况下都会导致 false
  3. 使用服务 onTaskRemovedonUnbind 方法:未被调用
  4. 在我的 AndroidManifest.xml 中,在服务元素中添加 android:stopWithTask="true":这确实会在滑动 Activity 时终止我的服务,但是 它导致:MyActivity 泄露了 ServiceConnection。不确定为什么,但我的猜测是我没有机会调用 unbindService()

我做错了什么或者我错过了什么?
谢谢。

最佳答案

正如 mklimek 已经提到的,onTaskRemoved() 是解决此问题的方法。

我在一个项目中使用它,该项目具有由 Activity 启动和绑定(bind)的绑定(bind)服务。以下是各个部分(为了安全起见,我将添加一些上下文):

ActivityonCreate() 调用自定义 startService()bindService() 辅助方法:

private void startService() {
    Intent myServiceIntent = new Intent(this, packageName.MyService.class);
    startService(myServiceIntent);
}

private void bindService() {
    mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mService = MyServiceListener.Stub.asInterface(iBinder);

            try {
                mService.registerCallback(myServiceCallback);
                mService.doSomething();
            } catch (RemoteException e) {
                MLog.w(TAG, "Exception on callback registration; Service has probably crashed.");
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mService = null;
        }
   };

    if(!myServiceIsBound) {
        Intent myServiceIntent = new Intent(this, packageName.MyService.class);
        bindService(myServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
        myServiceIsBound = true;
        // service is now bound
    } else {
        // service has already been bound
    }

}

现在,对于 Service 类:在它的 onCreate() 中,我显示一个通知(运行后台服务所需的 afaik)并设置 Binder:

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

    // Setup Binder for IPC
    mBinder = new MyServiceBinder();

    mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

    [...display notification code...] 
}

服务接口(interface)(告诉我这是否有趣,否则我就把它放在这里):

private class MyServiceBinder extends MyServiceListener.Stub {

    @Override
    public void registerCallback(MyServiceCallback callback) throws RemoteException {
         [...]
    }

    // further methods for the service interface...
}

我的 onTaskRemoved() 和其他生命周期方法如下所示:

@Override
public void onTaskRemoved(Intent rootIntent) {
    super.onTaskRemoved(rootIntent);

    // do something adequate here
}


// Lifecycle management
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_REDELIVER_INTENT;
}


// Binding
@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

@Override
public boolean onUnbind(Intent intent) {
    return super.onUnbind(intent);
}

每次我从最近的应用程序列表中滑动 Activity 时,我的 onTaskRemoved() 都会被调用。您确定未调用您的 onTaskRemoved() 方法(您是否在其中放置了一些日志记录代码)?还要确保在其中调用 super.onTaskRemoved() 方法。

除了我将 ServiceConnection 设置和服务绑定(bind)代码放入 Activity 之外,我们的代码看起来非常相似。您将很多这种逻辑移到了服务本身。

我只能猜测这可能是 Service 连接泄漏的问题,因为您的 ServiceConnection 是 Service 类的静态成员,并且您从 ServiceConnection 中维护对 Service 的引用(通过您的“实例” “多变的)。我不确定,但似乎两个链接都没有断开,当 Activity 终止时。请注意,在我的代码中,ServiceConnection 是 Activity 的成员,为了安全起见,我清除了 onServiceDisconnected() 中对 mService 的引用。或许您可以稍微重构一下,将 Activity 终止时无法进行 GC 处理的引用考虑在内。

关于android - 当 Activity 从最近的 Activity 中被刷掉时,优雅地清理绑定(bind)服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35459194/

相关文章:

java - Android 强制关闭 Google map

android - "GoogleApiClient is not connected yet"在使用 Firebase 身份验证和谷歌登录时注销

android - 整洁架构 : share same models/entities with different layers

Android - Google Play 的哪些权限为 "special"?

java - 无法按预期将我的 arrayList 写入文件

android - 如何在android中一次完成多个 Activity ?

android - 如何在没有 Logcat 应用程序的情况下在 Android 智能手机中查找 Activity 日志文件?

background - Whatsapp 或电报等应用程序如何监听 Android 上的来电/消息事件?

java - 当调用 Activity 被终止或销毁时,Android 服务将停止工作

java - 如何从服务检索偏好数据