1

I know that I can wait for a service start by doing

bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

where serviceConnection implements a callback that is called when the service starts. However, I need a service that is less killeable, that is, a service hat uses startForeground. But this can only work if I start my service with startService, which does not provide a way to pass a serviceConnection.

How can I wait for an android service to start?

Why I need it to start? Well, because I need to call things inside it by doing service.method1(); etc.

Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150
  • Hi, aren't promises an option to solve this? have the original method to return a promise and just wait for it to complete or be rejected – Camilo Casadiego Jun 02 '20 at 23:37
  • 1
    "How can I wait for an android service to start?" -- you can't. :Well, because I need to call things inside it by doing service.method1();" -- that may not be necessary, and I would focus your efforts on trying to remove this requirement. – CommonsWare Jun 02 '20 at 23:40
  • @CamiloCasadiego you mean wait in a loop? Could work, but how are services able to return promises? – Guerlando OCs Jun 02 '20 at 23:40
  • 1
    @CamiloCasadiego: The Android SDK does not have a `Promise` class. And, while I think people have ported the JavaScript `Promise` concept to Java, that would not help here. – CommonsWare Jun 02 '20 at 23:42
  • If all you are looking to do is to keep using `bindService()` while having that service be a foreground service, [Carles' answer](https://stackoverflow.com/a/62163347/115145) should work. I still suggest that you revisit your overall approach to services, though. – CommonsWare Jun 03 '20 at 00:47
  • @CommonsWare my mistake, I thought promises were also part of android but here you can find a way to handle this on android, I think the problem they solve is very similar to yours https://stackoverflow.com/questions/23164196/promises-for-android – Camilo Casadiego Jun 04 '20 at 21:13

1 Answers1

2

You can try to use both methods, first start the service with startForeground() and then use bindService() to wait for the service connection.

The service starts in the foreground and you can use the service methods.

Starting Service:

listenServiceIntent = new Intent(getApplicationContext(), ListenService.class);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

    //Start in Foreground
    ContextCompat.startForegroundService(this, listenServiceIntent);

    if (connection != null) {
        //Then bind service
        bindService(listenServiceIntent, connection, Context.BIND_AUTO_CREATE);
    }
}
else {
    startService(listenServiceIntent);
    if (connection != null) {
        bindService(listenServiceIntent, connection, Context.BIND_AUTO_CREATE);
    }
}

Waiting Connection:

private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected");

            ListenService.LocalBinder binder = (ListenService.LocalBinder) service;
            listenService = binder.getService();

            //HERE you can use service methods

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected");
        }
};

Create notificationChannel:

public static void createNotificationChannel(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    NOTIFICATION_CHANNEL,
                    NOTIFICATION_NAME,
                    NotificationManager.IMPORTANCE_HIGH
            );

            NotificationManager manager =    context.getSystemService(NotificationManager.class);
            if (manager != null) {
                manager.createNotificationChannel(serviceChannel);
            }
        }
    }

Push notification:

public static Notification pushNotification(Context context, String notificationText, Class classNotification) {

        Intent notificationIntent = new Intent(context, classNotification);

        PendingIntent pendingIntent = PendingIntent.getActivity(context,
                0, notificationIntent, 0);


        return new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
                .setContentTitle(context.getString(R.string.notification_title))
                .setContentText(notificationText)
                .setContentIntent(pendingIntent)
                .setSmallIcon(R.drawable.logosinfondo_mini)
                .setColor(Color.MAGENTA)
                .setAutoCancel(true)
                .build();
    }

In onCreate() inside your Service:

@Override
    public void onCreate() {
        super.onCreate();
        Lib.createNotificationChannel(this);
        startForeground(1, Lib.pushNotification(this, "Started", ListenActivity.class));
    }
Carles Ramos
  • 344
  • 3
  • 8
  • should I put the `startForeground` command on the service as well? `startService` and `bindService` call different things starts in the service. – Guerlando OCs Jun 03 '20 at 00:31
  • Also I see that you call `startForegroundService`, but as I recall, truly foreground services require a notification to indicate the app is on background. – Guerlando OCs Jun 03 '20 at 00:37
  • 1
    I show a notification when the service starts. inside onCreate() startForeground(1, Lib.pushNotification(this, "Starting...", ListenActivity.class)); – Carles Ramos Jun 03 '20 at 00:41
  • `Notification notification = new NotificationCompat.Builder(this, "CHANNEL_ID") .setStyle(new NotificationCompat.DecoratedCustomViewStyle()) .build(); startForeground(FOREGROUND_ID,notification);` – Guerlando OCs Jun 03 '20 at 00:53
  • I did this but I see no notification. This is inside the `onCreate` of the service. I also printed something before it just to show it was running `onCreate`. Do you have any idea? – Guerlando OCs Jun 03 '20 at 00:54
  • I edit my response, including my methods to show notifications, regards – Carles Ramos Jun 03 '20 at 08:28
  • Sorry for taking too much time to accept. Excelent answer! – Guerlando OCs Jun 19 '20 at 08:27