I want to check my location in service after 10 kilometers away from last know location. Is this possible to not request all time current location? (because now app is trying to get current location every time). If yes, how then? All my location code almost equals Best way to get user GPS location in background in Android answer code, which starting in service in main activity
2 Answers
Try to change Service class to IntentService
Other wise i provide my demo for show current location update every 10 sec using BroadcastReceiver. Also in this demo, I used notification show when location update.
like below code.
public class LocationUpdatesBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "LUBroadcastReceiver";
public static final String ACTION_PROCESS_UPDATES =
"com.google.android.gms.location.sample.backgroundlocationupdates.action" +
".PROCESS_UPDATES";
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_PROCESS_UPDATES.equals(action)) {
LocationResult result = LocationResult.extractResult(intent);
if (result != null) {
List<Location> locations = result.getLocations();
LocationResultHelper locationResultHelper = new LocationResultHelper(
context, locations);
// Save the location data to SharedPreferences.
locationResultHelper.saveResults();
// Show notification with the location data.
locationResultHelper.showNotification();
Log.i(TAG, LocationResultHelper.getSavedLocationResult(context));
}
}
}
}
}
then second class like below .. In this code show channel because running in android 8.0
/**
* this class used to show notification and store location data into shared preferences. */
public class LocationResultHelper {
final public static String KEY_LOCATION_UPDATES_RESULT = "location- update-result";
final private static String PRIMARY_CHANNEL = "default";
private Context mContext;
private List<Location> mLocations;
private NotificationManager mNotificationManager;
/**
* this constructor used to initialised this class.
* @param context
* @param locations
*/
public LocationResultHelper(Context context, List<Location> locations) {
mContext = context;
mLocations = locations;
NotificationChannel channel = new NotificationChannel(PRIMARY_CHANNEL,
context.getString(R.string.default_channel), NotificationManager.IMPORTANCE_DEFAULT);
channel.setLightColor(Color.GREEN);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
getNotificationManager().createNotificationChannel(channel);
}
/**
* this method used to report location with date and time.
*/
private String getLocationResultTitle() {
String numLocationsReported = mContext.getResources().getQuantityString(
R.plurals.num_locations_reported, mLocations.size(), mLocations.size());
return numLocationsReported + ": " + DateFormat.getDateTimeInstance().format(new Date());
}
/**
* this method used to give location data.
* @return
*/
private String getLocationResultText() {
if (mLocations.isEmpty()) {
return mContext.getString(R.string.unknown_location);
}
StringBuilder sb = new StringBuilder();
for (Location location : mLocations) {
sb.append("(");
sb.append(location.getLatitude());
sb.append(", ");
sb.append(location.getLongitude());
sb.append(")");
sb.append("\n");
}
return sb.toString();
}
/**
* this method save data into shared preferences.
*/
public void saveResults() {
PreferenceManager.getDefaultSharedPreferences(mContext)
.edit()
.putString(KEY_LOCATION_UPDATES_RESULT, getLocationResultTitle() + "\n" +
getLocationResultText())
.apply();
}
/**
* this method get shared preferences store location update.
*/
public static String getSavedLocationResult(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getString(KEY_LOCATION_UPDATES_RESULT, "");
}
/**
* Get the notification mNotificationManager.
* <p>
* Utility method as this helper works with it a lot.
*
* @return The system service NotificationManager
*/
private NotificationManager getNotificationManager() {
if (mNotificationManager == null) {
mNotificationManager = (NotificationManager) mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
}
return mNotificationManager;
}
/**
* Displays a notification with the location results.
*/
public void showNotification() { Intent notificationIntent = new Intent(mContext, MainActivity.class);
// Construct a task stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext);
// Add the main Activity to the task stack as the parent.
stackBuilder.addParentStack(MainActivity.class);
// Push the content Intent onto the stack.
stackBuilder.addNextIntent(notificationIntent);
// Get a PendingIntent containing the entire back stack.
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder notificationBuilder = new Notification.Builder(mContext,
PRIMARY_CHANNEL)
.setContentTitle(getLocationResultTitle())
.setContentText(getLocationResultText())
.setSmallIcon(R.drawable.common_google_signin_btn_icon_dark)
.setAutoCancel(true)
.setContentIntent(notificationPendingIntent);
getNotificationManager().notify(0, notificationBuilder.build());
}
}
then after make a third class for requestion location data
/** * this class used save user selected for request for location update and remove location update. */
public class LocationRequestHelper {
final static public String KEY_LOCATION_UPDATES_REQUESTED = "location-updates-requested";
public static void setRequesting(Context context, boolean value) {
PreferenceManager.getDefaultSharedPreferences(context)
.edit()
.putBoolean(KEY_LOCATION_UPDATES_REQUESTED, value)
.apply();
}
public static boolean getRequesting(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(KEY_LOCATION_UPDATES_REQUESTED, false);
}
}
then after make main activity and implement all the things.
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
/**
* The used for interval for location updates.
*/
private static final long UPDATE_INTERVAL = 10 * 1000;
/**
* The fastest interval to update for active location updates.
*/
private static final long FASTEST_UPDATE_INTERVAL = UPDATE_INTERVAL / 2;
/**
* The max time to wait for location update.
*/
private static final long MAX_WAIT_TIME = UPDATE_INTERVAL * 3;
/**
* Stores parameters for requests to the FusedLocationProviderApi.
*/
private LocationRequest mLocationRequest;
/**
* The entry point to Google Play Services.
*/
private GoogleApiClient mGoogleApiClient;
private Button mRequestUpdatesButton;
private Button mRemoveUpdatesButton;
private TextView mLocationUpdatesResultView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
/**
* this method initialized view control.
*/
private void initView() {
mRequestUpdatesButton = (Button) findViewById(R.id.request_updates_button);
mRemoveUpdatesButton = (Button) findViewById(R.id.remove_updates_button);
mLocationUpdatesResultView = (TextView) findViewById(R.id.location_updates_result);
// Check if the user revoked runtime permissions.
if (!checkPermissions()) {
requestPermissions();
}
buildGoogleApiClient();
}
@Override
protected void onStart() {
super.onStart();
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onResume() {
super.onResume();
updateButtonsState(LocationRequestHelper.getRequesting(this));
mLocationUpdatesResultView.setText(LocationResultHelper.getSavedLocationResult(this));
}
@Override
protected void onStop() {
PreferenceManager.getDefaultSharedPreferences(this)
.unregisterOnSharedPreferenceChangeListener(this);
super.onStop();
}
/**
* this method used to location data update settings.
*/
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates faster than this value.
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Sets the maximum time when batched location updates are delivered. Updates may be
// delivered sooner than this interval.
mLocationRequest.setMaxWaitTime(MAX_WAIT_TIME);
}
/**
* this method used to invoke google location service.
*/
private void buildGoogleApiClient() {
if (mGoogleApiClient != null) {
return;
}
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.enableAutoManage(this, this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.i(TAG, "GoogleApiClient connected");
}
/**
* this method call particular class or services
* if you used intent service then pass intent in class name LocationUpdatesIntentService
*if you used Broadcast service then pass intent in class name LocationUpdatesBroadcastReceiver
* @return
*/
private PendingIntent getPendingIntent() {
Intent intent = new Intent(this, LocationUpdatesBroadcastReceiver.class);
intent.setAction(LocationUpdatesBroadcastReceiver.ACTION_PROCESS_UPDATES);
return PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
@Override
public void onConnectionSuspended(int i) {
final String text = "Connection suspended";
Log.w(TAG, text + ": Error code: " + i);
showSnackbar("Connection suspended");
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
final String text = "Exception while connecting to Google Play services";
Log.w(TAG, text + ": " + connectionResult.getErrorMessage());
showSnackbar(text);
}
/**
* this method show snack bar notification.
*/
private void showSnackbar(final String text) {
View container = findViewById(R.id.activity_main);
if (container != null) {
Snackbar.make(container, text, Snackbar.LENGTH_LONG).show();
}
}
/**
* this method check permission and return current state of permission need.
*/
private boolean checkPermissions() {
int permissionState = ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION);
return permissionState == PackageManager.PERMISSION_GRANTED;
}
/**
* this method request to permission asked.
*/
private void requestPermissions() {
boolean shouldProvideRationale =
ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION);
if (shouldProvideRationale) {
Log.i(TAG, "Displaying permission rationale to provide additional context.");
Snackbar.make(
findViewById(R.id.activity_main),
R.string.permission_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View view) {
// Request permission
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_PERMISSIONS_REQUEST_CODE);
}
})
.show();
} else {
Log.i(TAG, "Requesting permission");
// previously and checked "Never ask again".
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_PERMISSIONS_REQUEST_CODE);
}
}
/**
* Callback received when a permissions request has been completed.
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
Log.i(TAG, "onRequestPermissionResult");
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
if (grantResults.length <= 0) {
// If user interaction was interrupted, the permission request is cancelled and you
// receive empty arrays.
Log.i(TAG, "User interaction was cancelled.");
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission was granted. Kick off the process of building and connecting
// GoogleApiClient.
buildGoogleApiClient();
} else {
// Permission denied.
Snackbar.make(
findViewById(R.id.activity_main),
R.string.permission_denied_explanation,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.settings, new View.OnClickListener() {
@Override
public void onClick(View view) {
// Build intent that displays the App settings screen.
Intent intent = new Intent();
intent.setAction(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package",
BuildConfig.APPLICATION_ID, null);
intent.setData(uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
})
.show();
}
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
if (s.equals(LocationResultHelper.KEY_LOCATION_UPDATES_RESULT)) {
mLocationUpdatesResultView.setText(LocationResultHelper.getSavedLocationResult(this));
} else if (s.equals(LocationRequestHelper.KEY_LOCATION_UPDATES_REQUESTED)) {
updateButtonsState(LocationRequestHelper.getRequesting(this));
}
}
/**
* Handles the Request Updates button and requests start of location updates also disable button after selected.
*/
public void requestLocationUpdates(View view) {
try {
Log.i(TAG, "Starting location updates");
LocationRequestHelper.setRequesting(this, true);
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, getPendingIntent());
} catch (SecurityException e) {
LocationRequestHelper.setRequesting(this, false);
e.printStackTrace();
}
}
/**
* Handles the Remove Updates button, and requests removal of location updates also disable button after selected.
*/
public void removeLocationUpdates(View view) {
Log.i(TAG, "Removing location updates");
LocationRequestHelper.setRequesting(this, false);
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,
getPendingIntent());
}
/**
* maintain button state is selected or not if selected then show disable.
*/
private void updateButtonsState(boolean requestingLocationUpdates) {
if (requestingLocationUpdates) {
mRequestUpdatesButton.setEnabled(false);
mRemoveUpdatesButton.setEnabled(true);
} else {
mRequestUpdatesButton.setEnabled(true);
mRemoveUpdatesButton.setEnabled(false);
}
}
}
then after add boradcast receiver into android manifest file between application tag..
<receiver
android:name=".notification.LocationUpdatesBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name=".notification.LocationUpdatesBroadcastReceiver.ACTION_PROCESS_UPDATES" />
</intent-filter>
</receiver>
In this demo used two button and it enable or disable mange by boolean value define in LocationRequestHelper.
more Information you need to refer below link.. https://codelabs.developers.google.com/codelabs/background-location-updates-android-o/index.html?index=..%2F..%2Findex#0
Not sure about distance but you can use JobScheduler that will work periodically (max 15 min)
otherwise you can use ForegroundService to get location all time.
Android Oreo will not allow to run background service for long time.

- 281
- 2
- 16