Why does service destroy when main process stops?

119 Views Asked by At

I am learning services these days and just experimenting around it and I don't have any intention to make Music player but just to learn about how do services work. So let me explain what I am doing.

My application is having one Activity and one Service extending Service class in which I have

@Override
public void onCreate()
{
    mediaPlayer=MediaPlayer.create(this,R.raw.serenity);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
    mediaPlayer.start();
    return 0;
}

And in my MainActivity class I am starting the Service on the main thread by

startService(intent);

And also I have added the attribute

<service
        android:name=".MusicService"
        android:process=":music"/>

To run the service in another process. Now I want to say that when I am starting the service with a button on activity class the service starts playing music although when i press back button the activity destroys and also music still play yeah that what I want but when I remove this app from recents then The music stops and get start with the beginning. Please tell me why this is happening. I don't want to music stop I want it to just play independent of activity or process of the application.

2

There are 2 best solutions below

3
On

If the service is currently executing code in its onCreate(), onStartCommand(), or onDestroy() methods, then the hosting process will be a foreground process to ensure this code can execute without being killed.

see:

https://developer.android.com/reference/android/app/Service.html#ServiceLifecycle

I know this thing but my question is that although being a foreground process as you said executing onStartCommand() it is getting stopped when I am clearing the application from recents the service it getting stopped once and getting started again from beginning. – Dushyant Suthar 14 hours ago

    • return START_STICKY as you want to recreate service on close / crash
    • and use startForeground(int,Notification);

as shows example:

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
         // log start
        logger.info(getServiceName(), " Service: start id " + startId + ": " + intent);
        /** set foreground */
        setForeground();
        /** run until explicitly stopped. */
        return START_STICKY;
    }


    private setForeground() {
        Intent intent = new Intent(this, NotStickyActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
        Notification noti = new, Notification.Builder(getApplicationContext())
              .setContentTitle("Pratikk")
              .setContentText("Subject")
              .setSmallIcon(R.drawable.ic_launcher)
              .setContentIntent(pendingIntent)
              .build();

       startForeground(1234, noti);     
    }
    • don't enable service in manifest
    • start service via code & use base context ( not an activity - because you will get an exception of leaked service )
    • you can also provide binder & bind to service from activity

example enable/start:

     /**
     * This method enables the Component (Receiver/Service) registered i
     * n the AndroidManifest file.
     */
     public static void enableComponent(Context context, Class<?> componentClass) {
        getLogger().debug("Enabling component {} request from {}", componentClass.getName(), StackTraceInfo.getInvokingClassName());

        ComponentName receiver;
        receiver = new ComponentName(context, componentClass);
        PackageManager pm = context.getPackageManager();

        pm.setComponentEnabledSetting(receiver,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
    }

     /**
    * start a service
    *
    * @param context      - context to start service
    * @param serviceClass - service class to start
    * @return If the service is being started or is already running, the
    * {@link ComponentName} of the actual service that was started is
    * returned; else if the service does not exist null is returned.
    */
    public static ComponentName startService(Context context, Class<?> serviceClass) {
        getLogger().info("Starting service {} by {}", serviceClass.getName(), StackTraceInfo.getInvokingClassName());
        Intent serviceIntent = new Intent(context, serviceClass);
        return context.startService(serviceIntent);
    }

Yeah brother, I managed to make my service foreground so that problem is solved, but as you said and also doccumentations said that when ever system is executing onStartCommand() then it is treated as foreground but as you know when I am clearing it from recents then it is getting killed. I don't understand the difference between the system treats it as foreground and we set it as foreground why the behavior is different among both of these. – Dushyant Suthar

A foreground service is a service that's considered to be something the user is actively aware of and thus not a candidate for the system to kill when low on memory.

A foreground service must provide a notification for the status bar, which is placed under the "Ongoing" heading, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.

1
On

To make your service more stable, you should create a foreground service. This would not kill the service the service every time your main process stops. I faced a similar problem, where in my process used to get killed and restart again when I stopped the main process. To avoid this I used a foreground service. The link below will let you implement and understand the foreground process easily. Hope this helps. Android-foreground service example