12

在 Android 上,我有一个Activity调用FirstActivity,它启动一个Service命名MyService来在后台执行网络操作。TheActivity和 theService一直通过调用方法相互通信。

现在,当用户从FirstActivityto导航时,不应终止或重新创建SecondActivity后台服务,而是保持活动状态并传递给现在与该服务进行通信的服务。SecondActivity

换句话说,Service只要两个Activitys 之一在运行,它就应该在运行,并且当用户在两个Activitys 之间导航时它不应该停止。

其中一个Activitys 将始终处于前台,在此期间,服务应该(最好)永远不会被杀死。我认为这应该不是问题,因为这两个Activity中的一个始终处于活动状态,因此 Android 知道该服务很重要,而不是必须被杀死的东西。

(如果没有办法阻止 Android 不时杀死并重新创建服务,我需要一种方法来优雅地恢复服务的完整状态。)

综上所述,两者的“组合”Service应该具有相同的寿命。Activity它应该从它们中的第一个开始,并且在它们都被摧毁之前停止。

那么以下代码对于该设置和目标是否正确?

public class MyService extends Service {

    public class LocalBinder extends Binder {
        public MyService getService() {
            return MyService.this;
        }
    }

    ...

}

public class FirstActivity extends Activity {

    private MyService mMyService;

    private ServiceConnection mMainServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            MyService mainService = ((LocalBinder) service).getService();
            mMyService = mainService;
            mMyService.setCallback(FirstActivity.this);
        }

        @Override
        public void onServiceDisconnected(ComponentName className) {
            mMyService = null;
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        startService(new Intent(FirstActivity.this, MyService.class));
    }

    @Override
    protected void onResume() {
        super.onResume();
        bindService(new Intent(FirstActivity.this, MyService.class), mMainServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mMainServiceConnection != null) {
            unbindService(mMainServiceConnection);
        }

        if (mMyService != null) {
            mMyService.setCallback(null);
        }

        if (!isUserMovingToSecondActivity) {
            stopService(new Intent(FirstActivity.this, MyService.class));
        }
    }

    @Override
    public void onBackPressed() {
        stopService(new Intent(FirstActivity.this, MyService.class));
        super.onBackPressed();
    }

    ...

}

public class SecondActivity extends Activity {

    private MyService mMyService;

    private ServiceConnection mMainServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            MyService mainService = ((LocalBinder) service).getService();
            mMyService = mainService;
            mMyService.setCallback(SecondActivity.this);
        }

        @Override
        public void onServiceDisconnected(ComponentName className) {
            mMyService = null;
        }
    };

    @Override
    protected void onResume() {
        super.onResume();
        bindService(new Intent(SecondActivity.this, MyService.class), mMainServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mMainServiceConnection != null) {
            unbindService(mMainServiceConnection);
        }
    }

    @Override
    protected void onDestroy() {
        ...
        stopService(new Intent(SecondActivity.this, MyService.class));
    }

    ...

}

Activity这是在s 的后台保证不会被杀死或重新创建的持久服务的最佳方法吗?

怎么样Context.BIND_AUTO_CREATE?在这里设置这个标志是否正确?那么Context.BIND_ADJUST_WITH_ACTIVITY——Context.BIND_WAIVE_PRIORITY我需要这些吗?

4

1 回答 1

7

(非常感谢@corsair992 的有用指点!)


如果活动总是按该顺序调用(即FirstActivity开始SecondActivity,而不是相反,那么您基本上应该尝试将服务的生命周期“绑定”到FirstActivity的生命周期。

一般来说(见后面的警告),这意味着:

  • 来电。startService()_FirstActivity.onCreate()
  • 来电。stopService()_FirstActivity.onDestroy()
  • 在两个Activity的/方法中调用bindService()/ (以获得对Binder对象的访问,并能够调用它的方法)。unbindService()onStart()onStop()

以这种方式启动的服务将一直处于活动状态,直到stopService()被调用并且每个客户端都解除绑定,请参阅管理服务的生命周期

这两条路径并不完全分开。也就是说,您可以绑定到已经使用 startService() 启动的服务。(...) 在这种情况下,stopService() 或 stopSelf() 在所有客户端解除绑定之前实际上不会停止服务。

和:

当最后一个客户端与服务解除绑定时,系统会销毁该服务(除非该服务也由 startService() 启动)。

使用这个基本策略,服务将一直FirstActivity存在(即它不会被破坏)。然而,重要的一点仍然存在:如果发生未明确处理的配置更改(例如屏幕旋转),将导致 Activity 自行重新启动,并且服务将被销毁(因为我们正在调用stopService()in onDestroy())。

为了防止这种情况发生,您可以isChangingConfigurations()在实际停止服务之前进行检查(因为onDestroy()由于这个原因而发生的回调意味着虽然这个 Activity 的特定实例正在被销毁,但它会在之后重新创建。

因此,完整的解决方案将类似于:

public class FirstActivity extends Activity
{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        startService(new Intent(this, MyService.class));
    }

    private ServiceConnection mServiceConnection = new ServiceConnection() { ... }

    @Override
    protected void onStart() {
        super.onStart();
        bindService(new Intent(this, MyService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        unbindService(mServiceConnection);
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        if (!isChangingConfigurations())
            stopService(new Intent(this, MyService.class));

        super.onDestroy();
    }

虽然SecondActivity只会实现onStart()/onStop()方法(以相同的方式)。


关于您的特定实现的一些注意事项:

  • 没有必要覆盖onBackPressed(),因为如果活动被销毁,则将调用必要的生命周期方法(另外,它可以在不按后退按钮的情况下完成,例如如果调用finish()它)。
  • 停止服务onDestroy()而不是让onPause()您不必检查isUserMovingToSecondActivity.
于 2014-12-21T21:28:26.010 回答