Android GPS Location Periodically - android

I want to create an App which fetch user's location in every 5 min between 9:00 AM to 9:00 PM. Now i am not able to think the flow. I am confused on:
Should i implement 2 repeating alarm managers , one for every 5 min and another one for time slot. ?
Or do it in a way, fire alarm every 5 min and check if it is in between time slot then only run location service and upload to server work. ?
Please help me with suggestions/advice. How to achieve this in best approach in terms of phone battery, efficiency.

You should not use Handler.postDelayer() for time intervals, longer than 30sec, because it may cause memory leaks. Develop a couple of strategies - one for short time intervals - less than 30 secs, which use Handler and another - with AlarmManager (for longer intervals).

refer https://codelabs.developers.google.com/codelabs/background-location-updates-android-o/index.html?index=..%2F..%2Findex#0
you can set update interval as 5 min in location request.it is compatible with Android "O" also.

Here I have created a service which gives current location at interval of 1 Minute.You can modify it as per your requirement-
Also add this in gradle file-
compile 'com.google.android.gms:play-services:9.4.0'
LocationService.class
import android.Manifest;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import java.text.SimpleDateFormat;
import java.util.Date;
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener, ActivityCompat.OnRequestPermissionsResultCallback {
protected static final String TAG = "location-updates";
private static final long day = 24 * 60 * 60 * 1000;
private static final long hours = 60 * 60 * 1000;
private static final long minute = 60 * 1000;
private static final long fiveSec = 5 * 1000;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
#Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(getApplicationContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(minute);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setSmallestDisplacement(0);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
#Override
public void onConnected(Bundle bundle) {
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(mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
//Location Listener
#Override
public void onLocationChanged(final Location location) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
String currentDateandTime = sdf.format(new Date());
Log.e("Location ", location.getLatitude() + " " + location.getLongitude() + " " + currentDateandTime);
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
boolean isGranted = false;
for (int i = 0; i < grantResults.length; i++)
if (permissions[i].equals(Manifest.permission.ACCESS_FINE_LOCATION) && (grantResults[i] == PackageManager.PERMISSION_GRANTED))
isGranted = true;
if (isGranted) {
startService(new Intent(this, LocationService.class));
} else {
}
}
}

Well you can use handler for querying the location, you can do something like this
Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
currentLocation = getCurrentUserLocation();
handler.postDelayed(this, 1000*60*5);
}
}
};
handler.postDelayed(runnable, 1000*60*5);
And for checking the time interval is between, you can set a Alarm manager for this task,
And once time limit is reached, you need to remove the handler callbacks by
handleLocation.removeCallbacksAndMessages(null);

Related

Android O kills my Service as soon as it goes to the background

I have read a lot of other similar questions, and have checked out the Android documentation on Background Execution Limits (https://developer.android.com/about/versions/oreo/background#services), and still could not find a solution. I have tried most of the phone's settings as well.
The issue:
I have an app, that is used to collect location data in the background. I am using a Service to achieve this. At the moment, it collects location data every 5 seconds. It works perfectly fine on my Nexus 5 (API 23); however, it only works on my Nexus 5X (API 27), when the application is in the foreground. As soon as it goes in the background it stops. So this has nothing to do with long running tasks in the background, as soon as I navigate away from the app, the service stops immediately.
Here is my service class code:
import android.app.Service;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import app.khash.climbcollector.DataBase.DataContract.DataEntry;
public class GPSService extends Service implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
com.google.android.gms.location.LocationListener {
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private static final String TAG = GPSService.class.getSimpleName();
#Override
public void onCreate() {
super.onCreate();
buildGoogleApiClient();
}//onCreate
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!mGoogleApiClient.isConnected())
mGoogleApiClient.connect();
return START_STICKY;
}//onStartCommand
#Override
public void onConnected(Bundle bundle) {
startLocationUpdate();
}//onConnected
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "onConnectionSuspended " + i);
}//onConnectionSuspended
#Override
public void onLocationChanged(Location location) {
//insert location to the database passing in the location object
insertDataToDb(location);
}//onLocationChanged
//method for adding the location data to db
private void insertDataToDb(Location location) {
final DateFormat dateFormat = new SimpleDateFormat("MM.dd.yyyy 'at' HH:mm:ss z");
//Current date and time using the format declared at the beginning
final String currentDateTime = dateFormat.format(Calendar.getInstance().getTime());
double lat = location.getLatitude();
double lng = location.getLongitude();
double alt = location.getAltitude();
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String key = getString(R.string.route_name_intent_extra);
String routeName = sharedPref.getString(key, "default");
// Create a new map of values,
ContentValues values = new ContentValues();
values.put(DataEntry.COLUMN_DATA_LATITUDE, lat);
values.put(DataEntry.COLUMN_DATA_LONGITUDE, lng);
values.put(DataEntry.COLUMN_DATA_ALTITUDE, alt);
values.put(DataEntry.COLUMN_DATA_DATE, currentDateTime);
values.put(DataEntry.COLUMN_DATA_ROUTE_NAME, routeName);
// Insert a new location into the provider, returning the content URI for the new location.
Uri newUri = getContentResolver().insert(DataEntry.CONTENT_URI, values);
// Show a toast message depending on whether or not the insertion was successful
if (newUri == null) {
// If the new content URI is null, then there was an error with insertion.
Log.v(TAG, "error saving data");
} else {
//since the insert method return the Uri of the row created, we can extract the ID of
//the new row using the parseID method with our newUri as an input. This method gets the
//last segment of the Uri, which is our new ID in this case and we store it in an object
// And add it to the confirmation method.
String id = String.valueOf(ContentUris.parseId(newUri));
// Otherwise, the insertion was successful and we can log
Log.v(TAG, "Successfully added: " + id);
}
}//insertDataToDb
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "onConnectionFailed ");
}//onConnectionFailed
private void initLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(2000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}//initLocationRequest
private void startLocationUpdate() {
initLocationRequest();
//check for location permission
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;
}//check permission
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}//startLocationUpdate
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();
}//buildGoogleApiClient
#Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.disconnect();
}//onDestroy
}//GPSService
I call the service from my main activity using this:
Intent serviceStartIntent = new Intent(this, GPSService.class);
startService(serviceStartIntent);
And stop it using this code:
Intent serviceStopIntent = new Intent(this, GPSService.class);
stopService(serviceStopIntent);
Here is the code I have tried using the JobScheduler.
public class GPSJobService extends JobService implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
com.google.android.gms.location.LocationListener {
private String TAG = GPSJobService.class.getSimpleName();
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private JobParameters mParam;
#Override
public void onCreate() {
Log.v(TAG, "onCreate called");
super.onCreate();
buildGoogleApiClient();
}//onCreate
#Override
public void onDestroy() {
Log.v(TAG, "onDestroy called");
super.onDestroy();
mGoogleApiClient.disconnect();
}//onDestroy
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG, "onStartCommand called");
if (!mGoogleApiClient.isConnected())
mGoogleApiClient.connect();
return START_STICKY;
}//onStartCommand
#Override
public boolean onStartJob(JobParameters params) {
Log.v(TAG, "onStartJob called");
if (!mGoogleApiClient.isConnected())
mGoogleApiClient.connect();
mParam = params;
return true;
}//onStartJob
#Override
public void onLocationChanged(Location location) {
//insert location to the database passing in the location object
insertDataToDb(location);
}//onLocationChanged
private void initLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(2000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}//initLocationRequest
private void startLocationUpdate() {
initLocationRequest();
//check for location permission
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;
}//check permission
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}//startLocationUpdate
//method for adding the location data to db
private void insertDataToDb(Location location) {
final DateFormat dateFormat = new SimpleDateFormat("MM.dd.yyyy 'at' HH:mm:ss z");
//Current date and time using the format declared at the beginning
final String currentDateTime = dateFormat.format(Calendar.getInstance().getTime());
double lat = location.getLatitude();
double lng = location.getLongitude();
double alt = location.getAltitude();
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String key = getString(R.string.route_name_intent_extra);
String routeName = sharedPref.getString(key, "default");
// Create a new map of values,
ContentValues values = new ContentValues();
values.put(DataEntry.COLUMN_DATA_LATITUDE, lat);
values.put(DataEntry.COLUMN_DATA_LONGITUDE, lng);
values.put(DataEntry.COLUMN_DATA_ALTITUDE, alt);
values.put(DataEntry.COLUMN_DATA_DATE, currentDateTime);
values.put(DataEntry.COLUMN_DATA_ROUTE_NAME, routeName);
// Insert a new location into the provider, returning the content URI for the new location.
Uri newUri = getContentResolver().insert(DataEntry.CONTENT_URI, values);
// Show a toast message depending on whether or not the insertion was successful
if (newUri == null) {
// If the new content URI is null, then there was an error with insertion.
Log.v(TAG, "error saving data");
} else {
//since the insert method return the Uri of the row created, we can extract the ID of
//the new row using the parseID method with our newUri as an input. This method gets the
//last segment of the Uri, which is our new ID in this case and we store it in an object
// And add it to the confirmation method.
String id = String.valueOf(ContentUris.parseId(newUri));
// Otherwise, the insertion was successful and we can log
Log.v(TAG, "Successfully added: " + id);
//finish the job
jobFinished(mParam, true);
}
}//insertDataToDb
#Override
public boolean onStopJob(JobParameters params) {
Log.v(TAG, "onStopJob called");
return false;
}//onStopJob
#Override
public void onConnected(#Nullable Bundle bundle) {
startLocationUpdate();
}//onConnected
#Override
public void onConnectionSuspended(int i) {
Log.v(TAG, "onConnectionSuspended called");
}//onConnectionSuspended
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.v(TAG, "onConnectionFailed called");
}//onConnectionFailed
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.addApi(LocationServices.API)
.build();
}//buildGoogleApiClient
}//GPSJobService
I am calling it in my main activity like this:
case R.id.bttn_job_start:
ComponentName serviceComponent = new ComponentName(this, GPSJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(mJobId, serviceComponent);
builder.setMinimumLatency(5000);
builder.setBackoffCriteria(5000, JobInfo.BACKOFF_POLICY_LINEAR);
//repeat every 5 seconds
// builder.setPeriodic(5000);
JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(builder.build());
Toast.makeText(this, "Started", Toast.LENGTH_SHORT).show();
break;
I have tried either setting latency and backoff criteria, or set as periodic (commented out right now). Both methods work while the app is in the foreground. Neither works when the app goes to the background.
As I mentioned earlier, it works perfect on my Nexus 5, but not on Nexus 5X.
Any suggestions on how I can fix this problem?
Thanks,
It is behaving as expected. Starting from Android o, while an app is in the foreground, it can create and run both foreground and background services freely. When an app goes into the background, it has a window of several minutes (based on my observations its around 1 - 2 minutes) in which it is still allowed to create and use services. The system stops the app's background services, just as if the app had called the services' Service.stopSelf() methods.
If the task need to be run through completion immediately and reliably the best alternative to this would be to use ForegroundService. You can follow this SO which describes this approach.
If the Job needs to be executed at later point of time when certain constraints are met, consider using JobScheduler or WorkManager.

Checking if value of a string exceeds a value

In my app, I have a speedometer class and I want to be able to say in my Broadcast Receiver class that when the speed goes over 25, do some action.
How would I go about doing that?
I have searched various questions but all lead me to a dead end.
Heres the Speedometer Code
package com.rrithvik.idrive;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import java.text.DecimalFormat;
import java.util.concurrent.TimeUnit;
/**
* Created by vipul on 12/13/2015.
*/
public class LocationService extends Service implements
LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final long INTERVAL = 1000 * 2;
private static final long FASTEST_INTERVAL = 1000 * 1;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mCurrentLocation, lStart, lEnd;
static double distance = 0;
double speed;
private final IBinder mBinder = new LocalBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
return mBinder;
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onConnected(Bundle bundle) {
try {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
} catch (SecurityException e) {
}
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
distance = 0;
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onLocationChanged(Location location) {
MainActivity.locate.dismiss();
mCurrentLocation = location;
if (lStart == null) {
lStart = mCurrentLocation;
lEnd = mCurrentLocation;
} else
lEnd = mCurrentLocation;
//Calling the method below updates the live values of distance and speed to the TextViews.
updateUI();
//calculating the speed with getSpeed method it returns speed in m/s so we are converting it into kmph
speed = location.getSpeed() * 2.24;
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
public class LocalBinder extends Binder {
public LocationService getService() {
return LocationService.this;
}
}
//The live feed of Distance and Speed are being set in the method below .
private void updateUI() {
if (MainActivity.p == 0) {
distance = distance + (lStart.distanceTo(lEnd) * 0.00062);
MainActivity.endTime = System.currentTimeMillis();
long diff = MainActivity.endTime - MainActivity.startTime;
diff = TimeUnit.MILLISECONDS.toMinutes(diff);
MainActivity.time.setText("Total Time: " + diff + " minutes");
if (speed > 0.0) {
MainActivity.speed.setText("Current speed: " + new DecimalFormat("#.##").format(speed) + " mph");
}
else {
MainActivity.speed.setText(".......");
}
MainActivity.dist.setText("Total Distance " + new DecimalFormat("#.###").format(distance) + " miles.");
lStart = lEnd;
}
}
#Override
public boolean onUnbind(Intent intent) {
stopLocationUpdates();
if (mGoogleApiClient.isConnected())
mGoogleApiClient.disconnect();
lStart = null;
lEnd = null;
distance = 0;
return super.onUnbind(intent);
}
}
So once again, this action has to be done in the Broadcast Receiver Class
Maybe this is what you are searching
double speedNum = Double.parseDouble(speed)
and then do the checking whether the speedNum is larger than 25 or not.
If you convert your String to a Double value, you will can verify this number.
double speedDouble = Double.parseDouble(speedText);
if(speedDouble > 25) {
// Do something
}

Backoff location requests in Google Play Services for Android

I am using the Google play services for android for requesting periodically the location of a user.
I created a background service that requests the location of a user and saves the location in the device internal storage.
So far everything works.
Now, I want to implement a back-off mechanism : the more stationary a user is, the less frequent the location updates should be ( and vice versa ).
PROBLEM : When I call the method requestLocationUpdates(GoogleApiClient client, LocationRequest request, LocationListener listener, Looper looper) a location request is made instantly ( without taking into account the new value of the interval in the LocationRequest object.
Source code :
/*
* Copyright (C) 2017 app
*/
package com.app.android.location.service;
import android.Manifest;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.app.android.location.data.LocationEvent;
import com.app.android.location.provider.LocationGson;
import com.app.android.location.provider.LocationHistoryProvider;
import com.app.android.location.utils.LocationUtils;
import com.app.android.share.utils.Logger;
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
public static final String TAG = "LocationService";
private GoogleApiClient mGoogleApiClient;
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private LocationHistoryProvider mLocationHistoryProvider;
private LocationRequest mLocationRequest = LocationRequest.create().setInterval(LocationUtils.DEFAULT_FASTEST_INTERVAL_MILLIS).setMaxWaitTime(LocationUtils.DEFAULT_FASTEST_INTERVAL_MILLIS).setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler implements LocationListener {
ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
buildAndConnectGoogleApiClient();
}
#Override
public void onLocationChanged(final Location location) {
final LocationEvent newestLocationEvent = new LocationEvent.Builder().setLocation(location).build();
Logger.warn(TAG, "onLocationChanged() called with: location = [" + newestLocationEvent + "]");
Logger.warn(TAG, "currentInterval " + LocationUtils.getCurrentFastestInterval());
LocationUtils.getLatestLocation(mLocationHistoryProvider, new LocationUtils.LocationEventFound() {
#Override
public void onLocationEventFound(LocationEvent latestLocationEvent) {
if (latestLocationEvent != null && LocationUtils.isLocationUnchanged(latestLocationEvent, newestLocationEvent)) {
Logger.debug(TAG, "latestLocationEvent Found");
// compare the newest location to the last location that we saved
updateLocationRequests(true);
} else {
Logger.debug(TAG, "latestLocationEvent Not Found");
// if we cannot find a previous item saved, then just save this new item
mLocationHistoryProvider.addLocation(newestLocationEvent);
}
}
});
}
}
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
mLocationHistoryProvider = LocationGson.getInstance();
}
#Override
public void onDestroy() {
super.onDestroy();
destroyAndDisconnectGoogleApiClient();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
private void destroyAndDisconnectGoogleApiClient() {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mServiceHandler);
mGoogleApiClient.disconnect();
}
}
protected synchronized void buildAndConnectGoogleApiClient() {
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
if (!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
private void updateLocationRequests(boolean backoff) {
if (backoff) {
long intervalMillis = Math.min(mLocationRequest.getInterval() * 2, LocationUtils.SLOWEST_INTERVAL_MILLIS);
Logger.warn(TAG, "backoff() called with: fastestIntervalMillis = [" + intervalMillis + "]");
mLocationRequest.setInterval(intervalMillis);
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mServiceHandler, mServiceLooper);
} else {
Logger.debug(TAG, "permissions for location not granted");
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Logger.warn(TAG, "onConnected() called with: bundle = [" + bundle + "]");
updateLocationRequests(false);
}
#Override
public void onConnectionSuspended(int i) {
Logger.warn(TAG, "onConnectionSuspended() called with: i = [" + i + "]");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult result) {
Logger.warn(TAG, "onConnectionFailed() called with: result = [" + result + "]");
}
}

Getting GPS updates using fused location in background service For ex(15 mins)?

I'm new for android development need to get gps location in background service without user interaction like for every 15 mins need to fetch the coordinates and send the results to server how can i achieve this. Then i tried fused location api syncadapter combination.It works, i'm getting coordinates but i need to use that location class in dedicated android-service how can i achieve this need to make that service run for ever 15 mins fetch the coordinates and send that result to server let me post my Google api client class.Please check below code i have tried.
import android.content.Context;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.FusedLocationProviderApi;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import java.text.DateFormat;
import java.util.Date;
/**
* Created by 4264 on 14-10-2016.
*/
public class Locationlistener implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,LocationListener {
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mCurrentLocation;
String mLastUpdateTime;
private Context context;
private static final long INTERVAL = 1000 * 10;
private static final long FASTEST_INTERVAL = 1000 * 5;
public Locationlistener(Context c)
{
context=c;
//show error dialog if GoolglePlayServices not available
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
public String lat(){
String lat=null;
if(mCurrentLocation==null){
Log.d("is null","null");
}
else {
lat=String.valueOf(mCurrentLocation.getLatitude());
}
return lat;
}
protected void startLocationUpdates() {
PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
Log.d("started", "Location update started ..............: ");
}
public void updateUI() {
Log.d("updated", "UI update initiated .............");
if (null != mCurrentLocation) {
String lat = String.valueOf(mCurrentLocation.getLatitude());
String lng = String.valueOf(mCurrentLocation.getLongitude());
Log.e("latw",lat);
Log.e("Long",lng);
} else {
Log.d("", "location is null ...............");
}
}
#Override
public void onConnected(Bundle bundle) {
Log.d("connected", "onConnected - isConnected ...............: " + mGoogleApiClient.isConnected());
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.d("failed", "Connection failed: " + connectionResult.toString());
}
#Override
public void onLocationChanged(Location location) {
Log.d("locationchanged", "Firing onLocationChanged..............................................");
mCurrentLocation = location;
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
updateUI();
}
}
It works in syncadapter but i need to make this in service how can i achieve this and another doubt if user turn off the gps how can i get location is it possible with network location updates thanks in advance!!
I would suggest you to use AlarmManager to wake up device and receive location as soon as possible (interval 0) then continue to sleep at each 15 minutes. So this approach better than non-stop service.
If user turns off the gps, you will be still getting (network provider) location updates but not accurate due to location settings aren't adequate. Also to solve this, you can use SettingsApi
When making a request to location services, the device's system settings may be in a state that prevents an app from obtaining the location data that it needs. For example, GPS or Wi-Fi scanning may be switched off.

Android: Intent Service

I am trying to obtain location by using Fused location provider api by implementing it in the intentservice class and at the same time i am starting a newtimertask in the same service.
so when intentservice gets called, the timertask starts and the googleapiclent gets connected to get the location.
i want that if the location is not availaible ,my timertask disconnects the googleapiclient in next 60 seconds.
But this doesnot work...if it doesnot get the location...the intent service keeps on running or the fusedlocatinprovider keeps for looking location.so i have to stop these?
package com.example.rj.intentlocationapi;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class BackgrndService extends IntentService implements LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mCurrentLocation;
LocationManager mlocationmanger;
int bool = 0;
CountDownTimer cnt;
public BackgrndService() {
super("BackgrndService");
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
private boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == status) {
return true;
} else {
return false;
}
}
#Override
protected void onHandleIntent(Intent intent) {
if (!isGooglePlayServicesAvailable()) {
stopLocationService();
}
mlocationmanger = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
cnt = new CountDownTimer(60000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
Log.w("haha", "going to finish it");
stopLocationService();
}
}.start();
mGoogleApiClient.registerConnectionCallbacks(this);
mGoogleApiClient.connect();
Log.w("haha", "blocked to finish it");
}
public void onConnected(Bundle bundle) {
Log.w("hello", "onConnected - isConnected ...............: " + mGoogleApiClient.isConnected());
startLocationUpdates();
}
protected void startLocationUpdates() {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
Log.w("hhaahaa", "Connection suspended stop here ");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.w("hhaahaa", "Connection failed stop here ");
}
#Override
public void onLocationChanged(Location location) {
Log.w("hello", "Firing onLocationChanged..............................................");
mCurrentLocation = location;
if (mCurrentLocation != null) {
Log.w("hi", mCurrentLocation.getLatitude() + " " + mCurrentLocation.getLongitude());
}
stopLocationService();
}
public void stopLocationService() {
Log.w("haha", "killing begins");
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
cnt.cancel();
Intent alarm = new Intent(this, BackgrndService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, alarm, 0);
if (bool == 0) {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
+ 1000 * 100, pendingIntent);
bool = 1;
}
}
}
Either you will shift or change Intent-Service to Service and use stopSelf() method to stop the service.This method stop the service.
IntentService automatically stops itself when onHandleIntent() ends, if no more commands had been sent to it while onHandleIntent() was running. Hence, you do not manually stop an IntentService yourself.

Categories

Resources