Get continuous location using service even after app killed from recent drawer - android

I started Service from main activity like;-
Intent intent = new Intent(this, MyLocationService.class);
startService(intent);
MyLocationService class looks like:-
public class MyLocationService extends Service implements
LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = MyLocationService.class.getSimpleName();
public static Location mCurrentLocation;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
#Override
public void onCreate() {
Log.e(TAG, "onCreate: ");
initiateGooglePlayService();
}
public void initiateGooglePlayService() {
Log.e(TAG, "initiateGooglePlayService: ");
if (isGooglePlayServicesAvailable()) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(10.0f);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind: ");
return null;
}
private boolean isGooglePlayServicesAvailable() {
Log.e(TAG, "isGooglePlayServicesAvailable: ");
int status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(getApplicationContext());
return ConnectionResult.SUCCESS == status;
}
#Override
public void onConnected(Bundle bundle) {
Log.e(TAG, "onConnected: ");
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "onConnectionSuspended: ");
}
protected void startLocationUpdates() {
Log.e(TAG, "startLocationUpdates: ");
try {
PendingResult<Status> pendingResult;
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
} catch (IllegalStateException ignored) {
}
}
#Override
public void onLocationChanged(Location location) {
Log.e(TAG, "onLocationChanged: " + location.getLongitude());
if (mGoogleApiClient.isConnected()) {
mCurrentLocation = location;
Intent intent = new Intent("GPSLocationUpdates");
intent.putExtra("location", location);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Toast.makeText(this, "location", Toast.LENGTH_LONG).show();
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed: ");
}
}
I never stop the service anywhere.
But still I am unable to get the control of onLocationChange().
My motive is that, I need continuous location to do some background operation. It worked in lollipop sometimes. But it is not working in Marshmallow and nougat and even kitkat also. I searched but could not get the proper idea. Please let me know, where i am going wrong. Any suggestion accepted.
I am using following dependency for location;-
compile 'com.google.android.gms:play-services-location:9.6.1'

You can use the HyperTrack SDK to get the location updates in the background. Get more insight about the reliability of SDK here in different conditions.
First Setup the SDK
After setting up the SDK you just need to set the Callback to receive the location updates.
HyperTrack.setCallback(new HyperTrackEventCallback() {
#Override
public void onEvent ( #NonNull final HyperTrackEvent event){
switch (event.getEventType()) {
case HyperTrackEvent.EventType.LOCATION_CHANGED_EVENT:
Log.d(TAG, "onEvent: Location Changed");
HyperTrackLocation hyperTrackLocation = event.getLocation();
LatLng latLng = hyperTrackLocation.getLatLng();
updateCurrentLocationMarker(event.getLocation());
break;
}
}
}
(Disclaimer: I work at HyperTrack.)

/**Check out my Github post i did the same for Taxi clone**/
Link ---> https://github.com/yash786agg/GPS/
Note: Remember to remove or comment the below mentioned code if you want the latitude
and latitude even when the application is in background.
if(networkUtilObj != null)
{
networkUtilObj.disconnectGoogleApiClient();
}

Related

Can not get accurate location while travelling in bus without internet

I am developing offline car tracker android application. It will update location after 5 min and stores it in SQLite.I used FusedLocationAPI but can not get accurate location while travelling in bus without Internet. I am getting accuracy 999m and getting same location after every 5 minutes.
I set alarm manager to 5 minutes.
public static void startAlarmManager(Context context)
{
preferences =context.getSharedPreferences(Constant.SHARED_PREF_NAME, Context.MODE_PRIVATE);
int duration= Integer.parseInt(preferences.getString(Constant.DURATION_SHARED_PREF,Constant.CONSTANT_DURATION_SHARED_PREF));
Log.d("duration",duration+"");
alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
gpsTrackerIntent = new Intent(context, GpsTrackerAlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(context, 0, gpsTrackerIntent, 0);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
5*60000,
pendingIntent);
}
It will fire broadcast receiver.
public class GpsTrackerAlarmReceiver extends WakefulBroadcastReceiver {
private static final String TAG = "GpsTrackerAlarmReceiver";
#Override
public void onReceive(Context context, Intent intent) {
LocationManager manager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE );
boolean statusOfGPS = manager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(statusOfGPS) {
context.startService(new Intent(context, LocationService.class));
}
}
}
This is location service. I am getting location with this way.
public class LocationService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private static final String TAG = "LocationService";
public static GoogleApiClient googleApiClient;
private LocationRequest locationRequest;
public Context context;
private DatabaseHelper db;
private boolean currentlyProcessingLocation = false;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
if (!currentlyProcessingLocation) {
currentlyProcessingLocation = true;
startTracking();
}
return START_NOT_STICKY;
}
private void startTracking() {
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (!googleApiClient.isConnected() || !googleApiClient.isConnecting()) {
googleApiClient.connect();
}
} else {
Log.e(TAG, "unable to connect to google play services.");
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG, "onConnected");
locationRequest = LocationRequest.create();
locationRequest.setInterval(1000); // milliseconds
locationRequest.setFastestInterval(1000); // the fastest rate in milliseconds at which your app can handle location updates
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, locationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "GoogleApiClient connection has been suspend");
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged");
startupdate(location);
}
private void startupdate(Location location) {
if (location != null) {
db=new DatabaseHelper(this);
db.insertLocation(location.getLatitude(), location.getLongitude(), "FusedApi Provider", location.getAccuracy());
stopLocationUpdates();
stopSelf();
}
}
public void stopLocationUpdates() {
if (googleApiClient != null && googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed");
stopLocationUpdates();
stopSelf();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Please help...if i am wrong. Thanks in advance.
When GPS is not practical you can use LocationManager.NETWORK_PROVIDER, this is location from the phone carrier that is less accurate than GPS but is available everywhere the carrier has a tower. The way I do it is a set a flag isGpsAvailable() to see if that is true I use GPS otherwise I use network provided location. This Google's doc provides detailed solutions including code snippets that you can use and change the way you it fits your needs.

Android gps location not getting updated periodically

I am using fusedlocation api in a Service for updating gps location to server every few seconds.In the MainActivity I have written the code to open locationSettings.Then in onResume method I start the Service(GpsService.java).The Service class send Broadcast everytime location is updated and it is received in the onResume() method.But I only get the location coordinates once.sendAmblnceGps() method is where the location is send to the server.
GpsService.java:
public class GpsService extends Service implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
com.google.android.gms.location.LocationListener locationListener;
LocationRequest mLocationRequest;
private static final long INTERVAL = 100* 50;
private static final long FASTEST_INTERVAL = 100 * 20;
GoogleApiClient googleApiClient;
boolean connected;
public GpsService() {
super();
}
#Override
public void onCreate() {
super.onCreate();
GoogleApiClient.Builder googleApiClientbuilder=new GoogleApiClient.Builder(GpsService.this).addConnectionCallbacks(GpsService.this).addOnConnectionFailedListener(GpsService.this).addApi(LocationServices.API);
googleApiClient=googleApiClientbuilder.build();
googleApiClient.connect();
Toast.makeText(getApplicationContext(),"service created",Toast.LENGTH_SHORT).show();
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(100);
}
protected void startLocationUpdates() {
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.
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, mLocationRequest, locationListener);
Log.d("TAG", "Location update started ..............: ");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("Service Command", "Started");
locationListener = new com.google.android.gms.location.LocationListener()
{
#Override
public void onLocationChanged(Location location) {
Intent intent = new Intent("location_updates");
intent.putExtra("lat", location.getLatitude());
intent.putExtra("longt", location.getLongitude());
Log.e("location", "lat:" + " " + Double.toString(location.getLatitude()) + " " + "Longt:" + " " + Double.toString(location.getLongitude()));
sendBroadcast(intent);
} };
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient,locationListener);
if(googleApiClient.isConnected()){
googleApiClient.disconnect();
}
Log.e("Service","Stopped");
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e("Connection failed","Service stopped");
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient,locationListener);
if(googleApiClient.isConnected()){
googleApiClient.disconnect();
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
createLocationRequest();
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
Log.e("Connection","suspended");
}
}
MainActivity.java:
#Override
protected void onResume() {
super.onResume();
if (locationManager == null) {
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
} else {
gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (isConnected()) {
if (gps_enabled) {
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Acquiring your current location");
progressDialog.setIndeterminate(true);
progressDialog.getWindow().setGravity(Gravity.CENTER);
progressDialog.show();
Log.e("starting", "service");
intent = new Intent(MainActivity.this, GpsService.class);
startService(intent);
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("starting", "broadcastservice");
latitude = Double.toString(intent.getDoubleExtra("lat", 0.0));
longitude = Double.toString(intent.getDoubleExtra("longt", 0.0));
if (isConnected()) {
sendAmblnceGps();
} else {
progressDialog.cancel();
Toast.makeText(getApplicationContext(), "Please enable internet connection", Toast.LENGTH_SHORT).show();
}
}
};
Log.e("registering", "broadcastservice");
registerReceiver(broadcastReceiver, new IntentFilter("location_updates"));
}
}
else {
Toast.makeText(getApplicationContext(),"Enable Internet Connection",Toast.LENGTH_SHORT).show();
}
}
}
You have specified mLocationRequest.setSmallestDisplacement(100);, so you need to move at least 100 meters from the location of the initial location update to have a new location update.

Recieved runtime permission for ACCESS_FINE_LOCATION, but still getting SecurityException

The flow goes like this. I get permission for Location(FINE and COARSE). OnPermissionGrantResult:
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case LOCATION:
if(grantResults[0] == 0){
(new AsyncTask<Void, Void, Void>(){
#Override protected Void doInBackground(Void... params){
getAndSetLocation();
}
}).execute();
}
break;
}
}
}
public void getAndSetLocation(){
startGPSService();
//GPS Tracker is the GPS Service
while(GPSTracker.location==null) {
try {
synchronized (lock) {
lock.wait();
}
} catch (InterruptedException e) {
Log.e(TAG, "getLocation: "+e.getLocalizedMessage() );
}
}
location = new Location(GPSTracker.location);
stopGPSService();
}
GPSTracker service
public class GPSTracker extends android.app.Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener {
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private static final String TAG = GPSTracker.class.getSimpleName();
public static Location location;
#Override
public void onCreate() {
super.onCreate();
buildGoogleApiClient();
Log.i(TAG, "onCreate");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
if (!mGoogleApiClient.isConnected())
mGoogleApiClient.connect();
return START_STICKY;
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "onConnected" + bundle);
Location l;
try {
l = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
}catch (SecurityException e){ //Error here
l = null;
}
if (l != null) {
Log.i(TAG, "lat " + l.getLatitude());
Log.i(TAG, "lng " + l.getLongitude());
location = l;
synchronized (lock) {
lock.notify();
}
}
startLocationUpdate();
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "onConnectionSuspended " + i);
}
#Override
public void onLocationChanged(Location location) {
Log.i(TAG, "lat " + location.getLatitude());
Log.i(TAG, "lng " + location.getLongitude());
GPSTracker.location = location;
lock.notify();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i(TAG, "onConnectionFailed ");
}
private void initLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(2000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
private void startLocationUpdate() {
initLocationRequest();
try {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}catch (SecurityException e){
Log.e(TAG, "startLocationUpdate: ", e);
}
}
private void stopLocationUpdate() {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.addApi(LocationServices.API)
.build();
}
}
Error is being thrown at onConnected even though, permission was received. Is it because the service is still not aware of the received permission or is it the way it is being executed? Or is the async task, the issue? It works fine from the second time on, but the first time, it always throws a security exception.
Exception Trace:
java.lang.SecurityException: Client must have ACCESS_FINE_LOCATION permission to request PRIORITY_HIGH_ACCURACY locations.
Code which requests permission:
public static boolean checkForPermissions(Activity context, String[] permissions, final int requestCode) {
if (permissions == null) return true;
boolean resultFlag = true;
final List<String> requiredPermissions = new ArrayList<>();
if (Build.VERSION.SDK_INT >= 23){
for (String permission : permissions) {
if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
requiredPermissions.add(permission);
resultFlag = false;
}
}
}
// Request all permissions at once..
if(requiredPermissions.size()!=0) {
requestPermissions(context, requiredPermissions.toArray(new String[0]), requestCode);
}
return resultFlag;
}
checkForPermissions(mContext, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION);
I think you need ACCESS_COARSE_LOCATION too.
reference
You forgot to connect to GoogleApiClient in GPSTracker
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
This will do.
last location is retrieved from location cache, now if you are starting app for first time there may not be any last location saved. in which case this line
l = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
returns null. now this only happens for first time because after that your app starts requesting updates and last location is no longer null.

How to optimise battery with FUSED LOCATION API - Android

Hi I am facing below issue/problem with location API in android
Battery consumption is high as 30% - 40%, which is causing lot of battery drain.
Location icon in status bar is always ON even when app is closed and when app is uninstalled it goes off automatically.
Requirement:
Need user location when app is opened.
I need to have users location even when app is not opened or not in use based on distance - need user location in background.
Approach:
with GPS
API used FUSED LOCATION API with pending intent.
LocationManager - to check state of GPS On/Off.
Code walkthru:
in OnCreate i m getting location manager instance - getting instance of location manager.
checking is GPS enabled or is network state available else show dialog to enable location: CODE: -
// get GPS state.
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (isGPSLocationEnabled(locationManager)) {
buildGooleLocationApiClient();
} else if (isNetworkLocationEnabled(locationManager)) {
buildGooleLocationApiClient();
} else {
showAlert();
}
Code for goolgeLocationAPiClient: In this method I am checking android version, requesting permission and enabling services
private void buildGooleLocationApiClient() {
if (Build.VERSION.SDK_INT >= 23) {
int isFineLocationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
int isCoarseLocationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION);
if (isFineLocationPermission == PackageManager.PERMISSION_DENIED || isCoarseLocationPermission == PackageManager.PERMISSION_DENIED) {
requestPermission();
} else {
checkGoogleLocationApiClient();
}
} else {
checkGoogleLocationApiClient();
}
}
Building GoogleAPI Client:
private void checkGoogleLocationApiClient() {
try {
if (mGoogleApiClient != null) {
if (mGoogleApiClient.isConnected()) {
getMyLocationCampaigns();
} else {
mGoogleApiClient.connect();
}
} else {
buildGoogleApiClient();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void getMyLocationCampaigns() {
if (mCurrentLocation != null) {
getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
} else {
try {
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
} catch (SecurityException ex) {
ex.printStackTrace();
getData("","");
}
}
}
private synchronized void buildGoogleApiClient() {
try {
Log.i(TAG, "activity Building GoogleApiClient===");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
} catch (Exception e) {
e.printStackTrace();
getData("","");
}
}
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(60 * 60 * 1000);
mLocationRequest.setFastestInterval(60 * 1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setSmallestDisplacement(100);
connectGoogleApiClient();
}
private void connectGoogleApiClient() {
if (mGoogleApiClient != null) {
if (!mGoogleApiClient.isConnected())
mGoogleApiClient.connect();
}
}
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (mCurrentLocation == null) {
try {
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mCurrentLocation != null) {
// MyAPICALL getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
} else {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,mLocationRequest, this);
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mCurrentLocation == null) {
if (locationManager != null) {
String provider = Utils.getUserLastLocation(locationManager);
if (provider != null) {
try {
Location location = locationManager.getLastKnownLocation(provider);
if (location != null) {
getData(location.getLatitude() + "", location.getLongitude() + "");
} else {
getData("", "");
}
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
} else {
getData(mCurrentLocation.getLatitude()+"",mCurrentLocation.getLongitude()+"");
}
}
} catch (SecurityException ex) {
ex.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
getData("","");
}
}
}
Method to getlocation in background with pending intent
private void startLocationUpdates() {
try {
Intent receiverIntentService = new Intent(this, LocationIntentService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 1, receiverIntentService, 0);
if (mGoogleApiClient != null) {
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, pendingIntent);
}
}
} catch (SecurityException se) {
se.printStackTrace();
}
}
BroadCastReceiver: In case if device is restarted:
public class LocationBroadcastReceiver extends BroadcastReceiver implements
GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener, LocationListener {
Context context;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;
protected Location mCurrentLocation;
public static Boolean mRequestingLocationUpdates = false;
SharedPreferences checkUserStatus;
public LocationBroadcastReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
try {
this.context = context;
checkUserStatus = context.getSharedPreferences(Params.LOGIN_DETAILS_PREFERENCE, 0);
String isUserLogedIn = checkUserStatus.getString(Params.TOKEN,"");
// if user is still logged in then only trigger background service
if (!isUserLogedIn.equals("")) {
buildGoogleApiClient();
if (mGoogleApiClient != null) {
if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) {
startLocationUpdates();
} else {
buildGoogleApiClient();
}
} else {
buildGoogleApiClient();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i("Broadcast receiver", "Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode());
}
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(60 * 60 * 1000);
mLocationRequest.setFastestInterval(60 * 1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setSmallestDisplacement(100);
}
protected void startLocationUpdates() {
try {
Intent receiverIntentService = new Intent(context,LocationIntentService.class);
PendingIntent pendingIntent = PendingIntent.getService(context,1,receiverIntentService,0);
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, pendingIntent);
}catch (SecurityException se) {
se.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
My intent service class: to get user updated location and make an API call
public class LocationIntentService extends IntentService {
Context context;
Bitmap myBitmap;
URL url;
SharedPreferences.Editor mMyLastLocationHolder;
SharedPreferences mMyLastLocation;
SharedPreferences checkUserStatus;
public LocationIntentService() {
super("LocationIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Location location = bundle.getParcelable("com.google.android.location.LOCATION");
if (location != null) {
context = getApplicationContext();
// API call to server
updateAPI(location.getLatitude()+"",location.getLongitude()+"");
Log.v("TAG LOCATION ", " ==== " + location.getLatitude() + " - " + location.getLongitude() + " ==== ");
Log.v("TAG LOCATION ", " ==== calling my-campaigns near me ========");
}
}
}
}
/**
* Handle action Foo in the provided background thread with the provided
* parameters.
*/
private void handleActionFoo(String param1, String param2) {
// TODO: Handle action Foo
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Handle action Baz in the provided background thread with the provided
* parameters.
*/
private void handleActionBaz(String param1, String param2) {
// TODO: Handle action Baz
throw new UnsupportedOperationException("Not yet implemented");
}
}
I hope this could help you finding the best solution/approach.
Personally prefer to use GoogleApiClient and LocationRequest with a certain priority and interval.
Write a service that implements the following interfaces:
GoogleApiClient.ConnectionCallbacks
GoogleApiClient.OnConnectionFailedListener
LocationListener
public class PositionService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {}
Use GoogleApiClient and LocationRequest classes.
Into the onCreate() instantiate a GoogleApiClient object, a LocationRequest object and make mGoogleApiClient connect.
public void onCreate() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
.setInterval(mInterval).setFastestInterval(mFastInterval);
mGoogleApiClient.connect();
}
Into the onDestroy() method make the mGoogleApiClient disconnect
#Override
public void onDestroy() {
mGoogleApiClient.disconnect();
}
Now implement the interfaces
#Override
public void onLocationChanged(Location location) {
Log.d("NewLocation", location.toString());
}
#Override
public void onConnected(#Nullable Bundle bundle) throws SecurityException {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
Now GoogleApiClient, based on the settings of the LocationRequest, will inform you of the position calling the onLocationChanged() callback
Your business logic should be placed into the onLocationChanged() method. Just pick a good interval timings and priority for the LocationRequest. (see documentation)
Please refer to the official documentation about location strategies, my solution is based on that.
I'm used to get the service started in Foreground to prevent unexpected behaviour by the operating system (e.g. service being killed)
This will only explain you the better logic
Instead of long running service or IntentService Just use Firebase JobDispatcher or Any 3rd Party lib Jobscheduler API such that you move all your location update code to Jobscheduler (https://github.com/googlesamples/android-JobScheduler/blob/master/Application/src/main/java/com/example/android/jobscheduler/service/MyJobService.java)
Start the Job as per your location update interval, configure or alter the Job as per your requirement !! it's really a better solution compare to long running service !!!(You can use eventBus or RxBus for location update in Activity or fragment !!)
Tips: every time Job starts with firing location update before Job closes setup up some system delay of 3seconds or more because some times Googleapiclient takes some more time to update the new updated GPS time after the delay you can close Googleapiclient all unwanted call backs with the running JobService. control the Job configuration smartly with Google Awareness Api or Google Fit API by detecting the User Activity!
All in one Job Jobscheduler Lib: https://github.com/evernote/android-job
P.S: code will be updated very soon
The documentation states
Activities should strongly consider removing all location request when
entering the background (for example at onPause()), or at least swap
the request to a larger interval and lower quality.
therefore what I did when I faced a similar issue was:
I created two location requests, the first had a priority of PRIORITY_HIGH_ACCURACY and an interval of 1 min while the second one had a priority of PRIORITY_LOW_POWER with an internal of 1 hour and a smallest displacement of 1km
When the app is launched I use the first location request (high priority) to get more frequent and accurate location updates
When the app enters the background I swap to the second location request (low priority) to eliminate the battery usage while getting less frequent location updates
(Optional) You can also get the battery percentage when the app is launched and choose according to a limit (eg. 15%) which location request you might want to use when the app is in the foreground
These steps helped me reduce the battery usage of my app from >30% to <3%.

Can able to stop location update, Android service

I am trying to create a route tracking app. it need to track location even if the app is in background. so i created a service and add code to this service. Following are my code. but there is one problem. I start the service from my main activity.
public void startTracking(View view) {
startService(new Intent(MainActivity.this, LocationIntentService.class));
}
public void stopTracking(View view) {
stopService(new Intent(MainActivity.this, LocationIntentService.class));
}
It start the service and locations are inserted to a local db. But i cant stop these service. When i stop service using above code it still track the location. How can i stop location update.
public class LocationIntentService extends IntentService implements LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = LocationIntentService.class.getSimpleName();
private static final long INTERVAL = 1000 * 10;
private static final long FASTEST_INTERVAL = 1000 * 5;
private static int DISPLACEMENT = 10;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
DBAdapter dbAdapter;
public LocationIntentService() {
super("LocationIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.e(TAG, " ***** Service on handled");
if (isGooglePlayServicesAvailable()) {
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
}
#Override
public void onConnected(Bundle bundle) {
Log.e(TAG, " ***** Service on connected");
startLocationUpdates();
openDB();
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG, " ***** Service on suspended");
mGoogleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
Log.e(TAG, "Location changed");
mLastLocation = location;
String latitude = String.valueOf(mLastLocation.getLatitude());
String longitude = String.valueOf(mLastLocation.getLongitude());
Log.e(TAG, " ##### Got new location"+ latitude+ longitude);
Time today = new Time(Time.getCurrentTimezone());
today.setToNow();
String timestamp = today.format("%Y-%m-%d %H:%M:%S");
dbAdapter.insertRow(latitude, longitude, timestamp);
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.e(TAG, "Connection failed: ConnectionResult.getErrorCode() = "
+ connectionResult.getErrorCode());
}
#Override
public void onDestroy() {
Log.e(TAG, "Service is Destroying...");
super.onDestroy();
if (mGoogleApiClient.isConnected()) {
stopLocationUpdates();
mGoogleApiClient.disconnect();
}
closeDB();
}
protected void stopLocationUpdates() {
Log.d(TAG, "Location update stoping...");
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
}
protected void startLocationUpdates() {
Log.d(TAG, "Location update starting...");
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
private void openDB() {
dbAdapter = new DBAdapter(this);
dbAdapter.open();
}
private void closeDB() {
dbAdapter = new DBAdapter(this);
dbAdapter.close();
}
protected void createLocationRequest() {
Log.e(TAG, " ***** Creating location request");
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
}
private boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == status) {
return true;
} else {
Log.e(TAG, " ***** Update google play service ");
return false;
}
}
}
The reason that it's not working for you is that you are using an IntentService, so calling stopService() will not cause onDestroy() to be called, presumably because it was already called after onHandleIntent() has completed. There is no need to ever call stopService() on an IntentService see here.
It looks like you should probably just use Service instead of IntentService. That way, when you call stopService(), it would call onDestroy() and unregister for location updates, as you expect.
The only other change you would need to make would be to override onStartCommand() instead of onHandleIntent().
You would have your class extend Service instead of IntentService, and then move your code to register for location updates to onStartCommand:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, " ***** Service on start command");
if (isGooglePlayServicesAvailable()) {
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
return Service.START_STICKY;
}
This way you can still call startService() and stopService(), and it should work as you are expecting.
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
call stopLocationUpdates() method in stopService()
When you stop your services. Then called this line in LocationIntentService.class.
locationManager.removeUpdates(this);

Categories

Resources