服务不断被破坏

Mai*_*aik 2 service lifecycle android

我有一项使用媒体播放器播放音乐的服务。该服务由一个活动启动,如果正在播放某些内容并且用户离开该活动,该服务应继续在后台播放。在前台运行服务似乎有效(我可以看到通知),但在几乎所有情况下,服务都会立即被销毁(服务上的系统调用 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);
    }
};
Run Code Online (Sandbox Code Playgroud)

我的 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);
}
Run Code Online (Sandbox Code Playgroud)

如果我离开活动,为什么服务会不断被破坏的任何想法?

Mai*_*aik 6

问题是 onCreate/onDestroy 中的绑定/解除绑定。我无法真正解释它,但是即使您在活动的 onCreate() 中使用 startService(),在该生命周期状态中进行绑定也会导致服务被破坏。

此设置现在运行良好:

  • 在活动的 onCreate() 中使用 startService() 来启动服务。
  • 服务的 onStartCommand() 必须返回 Service.START_STICKY
  • 在 Activity 的 onResume() 绑定到服务
  • 在 Activity 的 onPause() 中,如果正在播放某些内容,请调用服务的 startForeground() 并解除绑定。
  • 在 Activity 的 onDestroy() 调用 stopService() 如果当前没有播放。