服务一直被销毁

3
我有一个使用媒体播放器播放音乐的服务。该服务由一个活动启动,如果正在播放音乐并且用户从活动中移开,则服务应继续在后台播放。 将服务在前台运行似乎是有效的(我可以看到通知),但在几乎所有情况下,服务会立即被销毁(系统调用服务的OnDestroy)。 我知道使用startForeground并不意味着服务永远不会被杀死,但它一直很快地被销毁,所以我猜测系统强制杀死服务的资源太少不是原因。
这是我的实现方式: 在活动的OnCreate中,我启动(在后台)并绑定服务。在OnPause中,我将服务置于前台以防止其被销毁:
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_play);

    // start service
    startService(new Intent(this, MyService.class));
    // connect to service
    bindToService();
    ...
}

@Override
protected void onDestroy() {
    unbindFromService();
    super.onDestroy();
};

@Override
protected void onStart() {
    super.onStart();
}

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

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

    if (MediaPlayerService.getInstance().getStatus() == MEDIA_PLAYER_STATUS.Started) {
        // current playing something => keep service running
        mService.startForeground();
    } else {
        // stop service
        stopService(new Intent(MainActivity.this, MyService.class));
    }
}

@Override
protected void onResume() {
    super.onResume();

    // remove service from foreground
    if (mService != null) {
        mService.stopForeground();
    }
}

void bindToService() {
    // Establish a connection with the service. We use an explicit
    // class name because we want a specific service implementation that
    // we know will be running in our own process (and thus won't be
    // supporting component replacement by other applications).
    bindService(new Intent(MainActivity.this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);
    mIsBound = true;
}

void unbindFromService() {
    if (mIsBound) {
        // Detach our existing connection.
        unbindService(mConnection);
        mIsBound = false;
    }
}

private final ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName className, IBinder service) {
        // This is called when the connection with the service has been
        // established, giving us the service object we can use to
        // interact with the service. Because we have bound to a explicit
        // service that we know is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        mService = ((MyService.LocalBinder) service).getService();
        mService.registerClient(MainActivity.this);
    }

    @Override
    public void onServiceDisconnected(ComponentName className) {
        // This is called when the connection with the service has been
        // unexpectedly disconnected -- that is, its process crashed.
        // Because it is running in our same process, we should never
        // see this happen.
        mService = null;
        mService.unRegisterClient(MainActivity.this);
    }
};

我的Service中的start/stopForeground函数如下:

public void startForeground() {
    String songName = "blabla";
    // assign the song name to songName
    PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0,
            new Intent(getApplicationContext(), MainActivity.class),
            PendingIntent.FLAG_UPDATE_CURRENT);
    Notification notification = new Notification();
    notification.tickerText = songName;
    notification.icon = R.drawable.ic_launcher;
    notification.flags |= Notification.FLAG_ONGOING_EVENT;
    notification.setLatestEventInfo(getApplicationContext(), "MusicPlayerSample",
            "Playing: " + songName, pi);
    startForeground(NOTIFICATION_ID, notification);
}

public void stopForeground() {
    stopForeground(true);
}

有什么想法,为什么服务在我离开活动后会被销毁?
2个回答

7
问题在于在onCreate/onDestroy中进行绑定/解绑操作。 我无法很好地解释,但是在这些生命周期状态下进行绑定会导致服务被销毁,即使你在活动的onCreate()中使用startService()。
以下设置现在可以很好地工作:
  • 在活动的onCreate()中使用startService()来启动服务。
  • 服务的onStartCommand()必须返回Service.START_STICKY。
  • 在活动的onResume()中绑定服务。
  • 如果正在播放,则在活动的onPause()中调用服务的startForeground()并从中解除绑定。
  • 如果当前没有播放,则在活动的onDestroy()中调用stopService()。

这个救了我的命。在我的情况下,重要的是在MainActivity中解除绑定之前调用startForeground()。我寻找了好几天。谢谢! - EvanBlack

3
这是你的 答案

绑定服务只在其他应用程序组件绑定到它时运行。多个组件可以同时绑定到服务,但当它们全部解除绑定时,服务将被销毁。

你应该调用 startService()

你也可以将其与那个讨厌的静态数据成员结合使用。从onPause()中调用startService(),并让服务从onStartCommand()中将自己移动到前台。然后,摆脱mService - CommonsWare
感谢迄今为止的回答。但是如果我不绑定服务,我该如何与其通信?我需要从活动向服务发送命令(例如“播放文件xy”),并返回到“客户端”活动(例如“播放已停止”)。 - Maik
我再搜索了一下,在这里找到了一些答案:https://dev59.com/plbTa4cB1Zd3GeqP7Agt 但实际上,这或多或少就是我正在做的事情:我在 Activity 的构造函数中调用 startService,然后绑定它。那么为什么服务在我关闭 Activity 后仍然被杀死呢? - Maik
1
你的服务的onStartCommand()方法中是否返回了START_STICKY? - Luis
由于我已经使用startService()启动了服务,Leco的答案并不正确。问题似乎是我在错误的活动生命周期中绑定了服务。 是的,我使用了START_STICKY。 - Maik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接