My problem is i can get the location in background but once app is killed it stopped updating.
i am storing the latitude and longitude into firebase once it's fetching from getlastlocation method. and foreground and background mode it's updating fine. but when i close like clearing all the background apps then it is stop updating.
public class MyBackgroundLocationService extends Service {
private static final String TAG = MyBackgroundLocationService.class.getSimpleName();
private FusedLocationProviderClient mLocationClient;
private LocationCallback mLocationCallback;
public MyBackgroundLocationService() {
}
#Override
public void onCreate() {
super.onCreate();
mLocationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext());
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
Log.d(TAG, "onLocationResult: location error");
return;
}
List<Location> locations = locationResult.getLocations();
LocationResultHelper helper = new LocationResultHelper(getApplicationContext(), locations);
helper.showNotification();
helper.saveLocationResults();
Toast.makeText(getApplicationContext(), "Location received: " + locations.size(), Toast.LENGTH_SHORT).show();
}
};
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: called");
startForeground(1001, getNotification());
getLocationUpdates();
return START_STICKY;
}
private Notification getNotification() {
NotificationCompat.Builder notificationBuilder = null;
notificationBuilder = new NotificationCompat.Builder(getApplicationContext(),
App.CHANNEL_ID)
.setContentTitle("Location Notification")
.setContentText("Location service is running in the background.")
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true);
return notificationBuilder.build();
}
private void getLocationUpdates() {
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(4000);
locationRequest.setMaxWaitTime(15 * 1000);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
stopSelf();
return;
}
mLocationClient.requestLocationUpdates(locationRequest, mLocationCallback, Looper.myLooper());
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: called");
stopForeground(true);
mLocationClient.removeLocationUpdates(mLocationCallback);
}
}
so i am using foreground service to update location in background and it will show in notification those updates. once app is killed notification also disappeared. please please please anyone help me.
if you need more clear about question i will explain. please someone understand my pain
Related
I am trying to have an app give location updates while the app is in the background. When the app is open the service works fine. When the app is in the background the service continues running but the location updates stop. I have tried using a foreground service but this did not help.
I am using google's fusedLocationProviderClient
public int onStartCommand(Intent intent, int flags, int startId) {
client.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
}
With a location request defined in onCreate()
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(500);
locationRequest.setFastestInterval(500);
And callback defined as:
private final LocationCallback locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
List<Location> locationList = locationResult.getLocations();
if (locationList.size() != 0) {
Location location = locationList.get(0);
Log.e("AppLocationService", "Latitude - " +location.getLatitude()+", longitude - " +location.getLongitude() );
}
}
I'm really new to android studio so any help is much appreciated!
UPDATE:
Service started through startService()
public class BackgroundService2 extends Service {
private FusedLocationProviderClient client;
private LocationRequest locationRequest;
#Override
public void onCreate() {
super.onCreate();
client = LocationServices.getFusedLocationProviderClient(this);
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(500);
locationRequest.setFastestInterval(500);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent,flags,startId);
try {
if ( Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission( getBaseContext(), android.Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission( getBaseContext(), android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
client.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
}
} catch (SecurityException ignore) {
Log.e("AppLocationService", "SecurityException - " + ignore.toString(), ignore);
}
return START_STICKY;
}
private final LocationCallback locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
List<Location> locationList = locationResult.getLocations();
if (locationList.size() != 0) {
Location location = locationList.get(0);
Log.e("AppLocationService", "Latitude - " +location.getLatitude()+", longitude - " +location.getLongitude() );
}
}
};
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return null;
}
}
Turns out it was a problem with my manifest. Not only is it necessary to declare the service, but also its type.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
as well as
<service
android:name=".BackgroundService"
android:enabled="true"
android:exported="true"
android:foregroundServiceType="location" />
I want to develop a service that will work in background even the app gets killed. In my scenario I am getting location updates using fusedlocationproviderclient and sending it to database. The problem is that when I put app to background using home button location updates stop and approximately in 1 minute service gets killed. Again service gets killed if I kill the app from recent app tray. I have read that there are limitations for using fusedlocationproviderclient in background service. "If your app is running in the background, the location system service computes a new location for your app only a few times each hour." Is it related to this?
Service in manifest:
<service
android:name=".Background_Location_Service"
android:enabled="true"></service>
Here I start the service:
Intent service_intent=new Intent(getApplicationContext(),Background_Location_Service.class);
service_intent.putExtra("username",username);
startService(service_intent);
My service:
public class Background_Location_Service extends Service {
private static Double lat;
private static Double lon;
private FusedLocationProviderClient fusedLocationProviderClient;
private LocationCallback locationCallback;
private LocationRequest locationRequest;
private String username;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
username = intent.getExtras().getString("username");
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
locationRequest = LocationRequest.create();
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(5000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
lat = location.getLatitude();
lon = location.getLongitude();
//Sending latitude, longitude and username to database
Call<ResponseBody> call = Retrofit_Client
.getInstance()
.getAPI()
.send_location(lat, lon, username);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
String response_status = response.body().string();
Toast.makeText(Background_Location_Service.this, response_status, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(Background_Location_Service.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
};
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
}
//requesting updates
fusedLocationProviderClient.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper());
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
return Service.START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
fusedLocationProviderClient.removeLocationUpdates(locationCallback);
super.onDestroy();
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Intent restartService = new Intent(getApplicationContext(), this.getClass());
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartService, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME, 5000, pendingIntent);
}}
I learned, foreground service must be developed including notification to run a service continuously. With this approach can I achieve this? Or is there a better approach?
I read workmanager can be used so it will automatically deicide using jobscheduler or alarmmanager. Also it is able to cope with doze mode. So can I develop workmanager to get last known location periodically (E.g. every 5 minutes) instead of requesting location updates?
I'm Starting a Service(location service) at the beginning of app launch. But after staying on the App (approx. 5 to 10 minutes) I'm getting Waiting for a blocking GC Alloc error continuously and my app get stuck for a while then suddenly It crashes.
Also, When I run the app without Service it works smoothly.
I've been searching for many days but nothing solved my problem. I checked many related Q/A over Stack overflow but there are not seems to be any proper or valuable answers.
I also tried by added android:largeHeap="true" in manifests and multiDexEnabled true but these didn't help even.
Here's my Service class
public class LocationService extends IntentService {
private Context context;
private FusedLocationProviderClient fusedLocationClient;
private LocationRequest locationRequest;
Task<LocationSettingsResponse> task;
public static String NOTIFICATION_CHANNEL_ID = "com.example.simpleapp",
CHANNEL_NAME = "My Background Service";
public LocationService() {
super("LocationService");
}
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
startMyOwnForeground();
else startForeground(8, new Notification());
createLocationRequest();
context = this;
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
SettingsClient client = LocationServices.getSettingsClient(context);
task = client.checkLocationSettings(builder.build());
}
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
try {
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
} catch (SecurityException ignore) {
Log.e("AppLocationService", "SecurityException - " + ignore.toString(), ignore);
}
return Service.START_STICKY;
}
private final LocationCallback locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
List<Location> locationList = locationResult.getLocations();
if (locationList.size() != 0) {
Location location = locationList.get(0);
double latitude = location.getLatitude();
double longitude = location.getLongitude();
Intent intent = new Intent("location_update");
intent.putExtra("latitude", lat);
intent.putExtra("longitude", lng);
sendBroadcast(intent);
}
}
};
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
}
protected void createLocationRequest() {
locationRequest = LocationRequest.create();
locationRequest.setInterval(2000);
locationRequest.setFastestInterval(2000);
locationRequest.setPriority(CommonObjects.LOCATION_PRIORITY);
}
}
My Logcat
I have an android application that tracks customer location and send it's location each 10 seconds, however, in android O, location updates will be gotten few times each hour, as said in the documentation about limitation of gps location update in android O. anyway, to overcome this problem, I used a foreground service with notification, so that the gps location update keep updating in fusedLocation.
After that, I faced another problem that speed and direction in fusedLocation are zero, because it takes the location from both network provider and gps provider, when location is from network provider, the speed and direction are zeros, and these info are important for me, and I switched my location service to LocationManager instead of fusedLocation, so I can determine only the gps provider because this feature is not available in fusedLocation.
But what I notice, that LocationManager in android O does not get location updates while in the background even though I use foreground service for that purpose. how can get a solution that keep updating location in background, and use only gps provider?
I don't have a code snipt, I just want to discuss this matter.
Try the below line of code
Write the below line of code in the AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application>
<service
android:name=".LocationTracker"
android:stopWithTask="true"
/>
</application>
Write the line of code from where you want to start service
LocationTracker.startLocationService(getApplicationContext());
Write the below code in service class
public class LocationTracker extends Service{
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
private static int DISPLACEMENT = 0;
private FusedLocationProviderClient mFusedLocationClient;
private LocationRequest mLocationRequest;
private SettingsClient mSettingsClient;
private LocationSettingsRequest mLocationSettingsRequest;
private LocationCallback mLocationCallback;
private String TAG = LocationTracker.class.getSimpleName();
private final int NOTIFICATION_ID = 9083150;
public static final String CHANNEL_ID = "CHANNEL_ID";
public static final String CHANNEL_ID_NAME = "CHANNEL_ID_NAME";
#Override
public void onCreate() {
super.onCreate();
try {
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID_NAME,
NotificationManager.IMPORTANCE_HIGH);
channel.setSound(null, null);
channel.setShowBadge(false);
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.deleteNotificationChannel(CHANNEL_ID);
notificationManager.createNotificationChannel(channel);
Notification notification = createNotification(getApplicationContext(),CHANNEL_ID,0);
if (notification == null) {
notification = new NotificationCompat.Builder(this, CHANNEL_ID).build();
}
startForeground(NOTIFICATION_ID, notification);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private Notification createNotification(Context context, String channelid,int type) {
try {
return new NotificationCompat.Builder(context,channelid)
.setContentTitle("")
.setContentText("")
.setOnlyAlertOnce(true)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setVisibility(Notification.VISIBILITY_PRIVATE)
.setSmallIcon(R.mipmap.ic_launcher)
.build();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void setLocationUpdateCallback() {
try {
mLocationCallback = null;
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Logger.i(TAG, "locationResult ==== " + locationResult);
}
};
}catch (Exception e){
e.printStackTrace();
}
}
private void init() {
try {
setLocationUpdateCallback();
mFusedLocationClient = null;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mSettingsClient = LocationServices.getSettingsClient(this);
mLocationRequest = null;
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
mLocationSettingsRequest = null;
mLocationSettingsRequest = builder.build();
} catch (SecurityException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
init();
startLocationUpdates();
return START_STICKY;
}
#androidx.annotation.Nullable
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
protected void startLocationUpdates() {
mSettingsClient
.checkLocationSettings(
mLocationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
#SuppressLint("MissingPermission")
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.e(TAG, "LocationSettingsStatusCodes onSuccess");
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.e(TAG, "LocationSettingsStatusCodes.RESOLUTION_REQUIRED");
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.e(TAG, "LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE");
}
}
});
}
public static void startLocationService(Context context) {
try {
Intent intent = new Intent(context, LocationTracker.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(context, intent);
} else {
context.startService(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Hope it will help for you
I am working on application which requires to fetch location updates continuously in background service. I have used background sticky service with which it is working. But service is not starting after boot complete even though I have added boot broadcast and have started the service there. Service starts and immediately gets killed.
Also, this is not working on Oreo. Service stops after few minutes of application gets closed and never restarts till app is relaunched.
I have gone through lot of links, blogs which suggest to use AlarmManager/JobScheduler/JobIntentService but didn't get satisfactory solution.
So please suggest the working strategy/solution that can be used to continuously fetch location in background even after boot and should work on Oreo.
Using notification, you can make your service alive. It works up to android 8.1.
Below is code for background service
Note:
1) Use startForegroundService for above Build.VERSION_CODES.O
2) Use targetSdkVersion 25
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
mainActivity.startService(new Intent(getContext(), GpsServices.class));
} else {
mainActivity.startForegroundService(new Intent(getContext(), GpsServices.class));
}
BackgroundGpsServices Class
public class BackgroundGpsServices extends Service implements LocationListener {
private LocationManager mLocationManager;
public final long UPDATE_INTERVAL = 500; /* 0.5 sec */
public static final int NOTIFICATION_ID = 200;
#Override
public void onCreate() {
sendNotification(this, false);
startLocationUpdates();
}
private void startLocationUpdates() {
if (!isLocationUpdateRunning) {
isLocationUpdateRunning = true;
mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
if (mLocationManager != null) {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, UPDATE_INTERVAL, 0, this);
}
}
}
#Override
public void onLocationChanged(Location location) {
sendNotification(BackgroundGpsServices.this, true);
System.out.println("onLocationChanged ----- location=" + location);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
public static void sendNotification(Service service, boolean isUpdate) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Intent intent = new Intent(service, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(service, 0, intent, PendingIntent.FLAG_NO_CREATE);
NotificationCompat.Builder mNotifyBuilder = new NotificationCompat.Builder(service)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("INFO_NOTIFICATION_TITLE")
.setOngoing(true)
.setAutoCancel(false)
.setContentText("INFO_NOTIFICATION_MESSAGE")
.setContentIntent(pendingIntent);
Notification notification = mNotifyBuilder.build();
if (isUpdate) {
NotificationManager notificationManager = (NotificationManager) service.getSystemService(NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.notify(NOTIFICATION_ID, notification);
}
} else {
service.startForeground(NOTIFICATION_ID, notification);
}
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
/* Remove the locationlistener updates when Services is stopped */
#Override
public void onDestroy() {
try {
stopLocationUpdates();
stopForeground(true);
} catch (Exception e) {
e.printStackTrace();
}
}
private void stopLocationUpdates() {
isLocationUpdateRunning = false;
if (mLocationManager != null) {
mLocationManager.removeUpdates(this);
}
}
}
You can use fused location provider to get the location of the device at regular intervals. There is a direct approach to request periodic updates from the fused location provider. The accuracy of the location is determined by the providers, the location permissions you've requested, and the options you set in the location request.
Request location updates
Before requesting location updates, your app must connect to location services and make a location request. The lesson on Changing Location Settings shows you how to do this. Once a location request is in place you can start the regular updates by calling requestLocationUpdates().
Depending on the form of the request, the fused location provider
either invokes the LocationCallback.onLocationChanged() callback
method and passes it a list of Location objects, or issues a
PendingIntent that contains the location in its extended data. The
accuracy and frequency of the updates are affected by the location
permissions you've requested and the options you set in the location
request object.
This lesson shows you how to get the update using the LocationCallback
callback approach. Call requestLocationUpdates(), passing it your
instance of the LocationRequest object, and a LocationCallback. Define
a startLocationUpdates() method as shown in the following code sample:
#Override
protected void onResume() {
super.onResume();
if (mRequestingLocationUpdates) {
startLocationUpdates();
}
}
private void startLocationUpdates() {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback,
null /* Looper */);
}
Read Official Documentation here for detailed description.