Background Location Service — Android
A background service that collects user location even if app is closed.
Most of the time when I tried to search how to use background service in android it makes me upset, because no such helpful content is available except for developer docs.
So, I tried to built such a sample app which explains a lot better. Let’s take a quick tour.
Let’s code 🐒
- Create a new class which will hold service related stuffs, also implements LocationListener so that we can use helper methods provided by it.
public class BgLocationService extends Service implements LocationListener {}// Implement all the override methods - we'll need it later
- Now, add these variables to that class, before the constructor
boolean isGPSEnable = false;
boolean isNetworkEnable = false;
double latitude, longitude;
LocationManager locationManager;
Location location;
public static String str_receiver = "bgLocationService.receiver";
Intent intent;//Constructor
public BgLocationService() {}
As, you know running services without notification 😂, So gonna add some helper functions inside this class.
// Notification Channel
private String createNotificationChannel(String channelId, String channelName) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
channelId,
channelName,
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
return channelId;
}// Notification
private void updateNotification(String text) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
String channelId = createNotificationChannel("my_service", "My Background Service");
Notification notification = new NotificationCompat.Builder(this, channelId)
.setContentTitle("Background Service Running")
.setContentText(text)
.setSmallIcon(R.drawable.icon)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
}
Now, you have probable got an error saying (R.drawable.icon) is not found, so create one in drawable folder.
Okay, so we are done with writing notification helper methods, now its time to focus on getting user’s location update.
// Fetching geolocation
private void fn_getlocation() {
// Enabling location service
locationManager = (LocationManager) getApplicationContext().getSystemService(LOCATION_SERVICE);
isGPSEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
isNetworkEnable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnable && !isNetworkEnable) {
// If nor internet OR GPS is available -- maybe he(s) on another planet --
} else {
// If internet is connected
if (isNetworkEnable) {
location = null;
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 1, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
fn_update(location);
}
}
}
// If GPS is enabled
if (isGPSEnable) {
location = null;
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
fn_update(location);
}
}
}
}
}// Sends data back to activity
private void fn_update(Location location) {
intent.putExtra("latutide", location.getLatitude() + "");
intent.putExtra("longitude", location.getLongitude() + "");
sendBroadcast(intent);
}
Noticed? we just added a method fn_update() which sends back data to calling/parent activity.
Yay! Good Job 🏆
Now we can call this methods and see what’s there.
Remember all the override methods I told you we will need it later, well now its really a good time to use.
// when the service is created
@Override
public void onCreate() {
super.onCreate();
intent = new Intent(str_receiver);
}// when the service is started
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Fetching location for the first time.
fn_getlocation();
// Create the notification for the first time.
// later it can be updated by overriding
updateNotification("Starting background service...");
return super.onStartCommand(intent, flags, startId);
}// when the service is destroyed
@Override
public void onDestroy() {
// Remove the listener otherwise it will continue to post location update.
// even if the Service is destroyed
locationManager.removeUpdates(this);
super.onDestroy();
}
- Now, when user changes its location, a listener we already added LocationListener will now help us to update UI and Notification.
// when location is changed
@Override
public void onLocationChanged(Location location) {
// Update the UI if mounted
fn_update(location);
// Update the notification if running in background
updateNotification("Lat: " + location.getLatitude() + ", Lng: " + location.getLongitude());
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
All Done 🎉
Still having error check out the code.
Now, its time to call the service from the activity you are using, in my case its MainActivity
// Starting the service
Intent intent = new Intent(getApplicationContext(), BgLocationService.class);
startService(intent);// Stopping the service
Intent intent = new Intent(getApplicationContext(), BgLocationService.class);
stopService(intent);
Well, you can start/stop service as your own requirement, maybe conditionally.
Well, if you want the results to be displayed in ui.
// Broadcast Receiver, returns result from service
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Receiving data from service
double lat = Double.valueOf(intent.getStringExtra("latutide"));
double lng = Double.valueOf(intent.getStringExtra("longitude"));
// Updating the ui
latitude.setText(lat + "");
longitude.setText(lng + "");
}
};
That’s just the code for service, 😳 now if you really want to try this out check out my code.