Domanda

I have a service that uses media player to play some music. The service is started by an activity and if something is playing and the user moves away from the activity the service should keep playing in the background. Running the service in the foreground seems to work (I can see the notification), but in close to all cases the service is destroyed immediately (OnDestroy called by the system on the service). I know using startForeground does not mean that the service is never killed, but it keeps getting destroyed right away, so I guess too few ressources forcing the system to kill it, is not the reason for that.

This is how I implemented it: In OnCreate of the activity, I start (in the background) and bind the service. In OnPause I bring the service to the foreground to not get destroyed as well:

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);
    }
};

And the start/stopForeground functions in my Service look like this:

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);
}

Any ideas why the service keeps getting destroyed if I move away from the activity?

È stato utile?

Soluzione

The problem is the bind/unbind in onCreate/onDestroy. I can't really explain it, but binding in that lifecycle states leads to getting the service destroyed even though you use startService() in onCreate() of the activity.

This setup now works nicely:

  • In activity's onCreate() use startService() to get the service started.
  • The onStartCommand() of the service has to return Service.START_STICKY
  • In Activity's onResume() bind to the service
  • In Activity's onPause() if something is playing, call startForeground() of the service and unbind from it.
  • In Activity's onDestroy() call stopService() if nothing is currently playing.

Altri suggerimenti

Here's your answer.

A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed.

You should call startService() instead.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top