Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clarification on Android foreground service

Tags:

android

My app currently uses a background service to communicate (Bluetooth) with a physical device. (I manufacture and sell the physical device.) The app sends a command to the device every 500ms. The user starts this process and it must run until the user stops it. While the app is active, results of the process are sent to the app. This process needs to run even if the app is not active. (i.e. they take a phone call, search the web.) Once the app becomes active again, the state of the process is synced with the app. The process can run anywhere from a few minutes to many hours. (Yes, the user would need to plug in if they want to run the process for 99hrs.) Most users run it for 2-15min. All is fine for now, but with API 26, it looks like this architecture is no longer allowed. One migration option is to move to a foreground service. However, I find the documentation to be unclear on how foreground services work. Does the foreground service continue to run with the app is not active? (i.e. it has gone through onPause.) If so, how is this any different than a background service? Is there better documentation on how the foreground service works. (My web searches have not turned up anything significant.) Alos, the API 26 documentation does not say if the app is bonded to the background service if the new limitations still apply. Do they?

Thanks, Stan

like image 406
StanGreen Avatar asked Dec 15 '17 01:12

StanGreen


1 Answers

A Foreground Service is a Service that you put in the foreground state, that means, the system will not kill the process if it needs CPU or if your app is closed.

First you have 3 kinds of Services:

  • Started Services (runs in the UI thread)
  • IntentService (runs in its own thread) (See Services vs IntentServices)
  • Bound Services (runs as long as there's one activity active that bound it)

As said above, if you close your app, a Bound Service will be closed too, it is launched by bindService().

IntentServices are a subtype of Service which simplify a "work queue process" for incoming intents, i.e it handles incoming intents one by one within a queue, as said in the IntentService description. It has a default implementation and is launched by startService(). It is mainly for asynchronous tasks.

A Started Service is a Service started by a component, and continue to live until stopService() is called or your app is closed.

Using a Foreground Service makes your Service persistent. You have to call startForeground() inside your service. It will still run until you stop your Service, e.g with stopSelf() or stopService();

Note that onStartCommand() will be triggered each time you call startService() but onCreate() is triggered only once.

Here is a simple implementation of a Foreground Started Service:

In your Manifest.xml:

<service android:name=".ConnectionService"
    android:enabled="true"/>

In MyService.java:

public class MyService extends Service {
    // Unique notification identifier
    private final static int NOTIFICATION_ID = 95;

    private NotificationManager mNotificationManager;

    public MyService() { super(); }

    @Override
    public void onCreate() {
        // Initialize notification
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);

        // Build your notification here
        mBuilder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
        mBuilder.setSmallIcon(R.mipmap.ic_small_icon);
        mBuilder.setContentTitle("MyService");
        mBuilder.setContentText("The Service is currently running");

        // Launch notification
        startForeground(NOTIFICATION_ID, mBuilder.build());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Handle startService() if you need to
        // for exmple if you are passing data in your intent
        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // We don't provide binding, so return null
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // Remove the notification when the service is stopped
        mNotificationManager.cancel(NOTIFICATION_ID);
    }
}

Finally just call startService().

like image 140
Diego D. Avatar answered Sep 30 '22 06:09

Diego D.