Sample code for Android8.0 to adapt to foreground location service service

  • 2021-09-16 08:16:15
  • OfStack

Starting from Android 8.0, in order to reduce power consumption, the system limits the frequency of obtaining user location information by background applications, and only allows updating location information several times per hour. Please refer to the official instructions for details. According to the official guidelines, if you want to increase the frequency of location updates, you need the background application to provide a foreground service notification.

Therefore, the original use of locationManager to obtain the current location can not be used in the background. So I plan to use a foreground service, and I can get the current location when app is in the background.

I checked several blogs saying that the foreground service needs to call startForeground (int, Notification) in the onStartCommand method of service to start the foreground service.

However, onStartCommand needs to go through the life cycle of startservice () before it can be called.

I switched to bindservice (), which requires activity and service interactions, although the two startup methods can be mixed. But there is no need.

All I need is an service bound to the control and I don't want to handle the end of the service.

1. activity/fragment call binding service


Intent serviceIntent = new Intent(this, ForegroundLocationService.class);
bindService(serviceIntent, conn, Service.BIND_AUTO_CREATE);
//  Require incoming when binding services 1 A ServiceConnection Objects that implement classes 
//  When binding a service, the service's onBind Method, which returns the 1 A Ibinder Object to give activity / fragment Adj. onServiceConnected() From which methods in the service can be accessed 
  ServiceConnection conn = new ServiceConnection() {
    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    }
  };

2. I called startForeground in the onBind () method (int, Notification)

The first parameter is a positive integer that is not 0 and represents the id of the notification, and the second parameter represents the notification to be displayed.

Adapting 8.0 Notification builds need to be adapted, otherwise your notifications will not be displayed (the first time you called it, you thought it was 1 plus blocking notifications)

3. At this time, the foreground service should have been realized, and the location information obtained by the service needs to be transmitted to activity. (You can get it by calling locationmanager directly, and the location implementation is hidden here)


  public class MyBinder extends Binder {
    public ForegroundLocationService getService(){
      return ForegroundLocationService.this;
    }
  }
  // Pass binder Implementation caller client And Service Communication between 
  private MyBinder binder = new MyBinder();
  // Pass service Adj. onBind() Method returns the MyBinder Object that can obtain the current Service
  @Override
  public IBinder onBind(Intent arg0) {
    NotificationUtils notificationUtils = new NotificationUtils(this);
    startForeground(111, notificationUtils.getNotification("Notice", "Continuous positioning",null));
    return binder;
  }

4. Then you need to interact with the control and service, which is divided into three methods

When service is obtained, act actively calls to obtain data Callback is set in service, and service actively transfers data to act Transmission of data by broadcast.

  ServiceConnection conn = new ServiceConnection() {

    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // Through this method, you can get service That can be continuously updated by setting callbacks 
        ForegroundLocationService foregroundLocationService = ((ForegroundLocationService.MyBinder) service).getService(); 
        foregroundLocationService.setLocationCallback(new ForegroundLocationService.LocationCallback() {
          @Override
          public void onLocation(Location location) {

        }
      }) ; 
    }
  };

Write the interface in service and call it in the callback method that gets the location.


  public interface LocationCallback {
    /**
    *  Current position 
    */
    void onLocation(Location location);
  }
  private LocationCallback mLocationCallback;
  private class LocationListener implements android.location.LocationListener {
    public LocationListener(String provider) {
      Logger.e(TAG, "LocationListener " + provider);
    }
    @Override
    public void onLocationChanged(Location location) {
      Log.i("location", "onLocationChanged: " + " Current coordinates: " + location.getLatitude() + " : " + location.getLongitude());
      if(mLocationCallback!=null){
        mLocationCallback.onLocation(location);
      }
    }
  }

Service sends messages to Activity, using broadcast, although Activity registers the appropriate receiver. For example, if Service wants to send the same message to multiple Activity, it is better to use this method, so it will be omitted here. For details, please refer to the following articles.

Reference article: https://www.ofstack.com/article/123316. htm


Related articles: