Поскольку я хочу вычислять расстояние каждые две минуты, но в Oreo, когда приложение переходит в спящий режим, оно не работает.Вот почему я добавил уведомление в сервис, когда приложение переходит в фоновый режим, уведомление отправляется пользователю, поэтому оно работает нормально, когда приложение также переходит в спящий режим.
Без уведомления, как это сделать в сервисе Android, пожалуйста, помогите мне исправитьмоя проблема.
Сервисный код:
/**
* A bound and started service that is promoted to a foreground service when location updates have
* been requested and all clients unbind.
*
* For apps running in the background on "O" devices, location is computed only once every 10
* minutes and delivered batched every 30 minutes. This restriction applies even to apps
* targeting "N" or lower which are run on "O" devices.
*
* This sample show how to use a long-running service for location updates. When an activity is
* bound to this service, frequent location updates are permitted. When the activity is removed
* from the foreground, the service promotes itself to a foreground service, and location updates
* continue. When the activity comes back to the foreground, the foreground service stops, and the
* notification assocaited with that service is removed.
*/
public class LocationUpdatesService extends Service {
private static final String PACKAGE_NAME =
"com.google.android.gms.location.sample.locationupdatesforegroundservice";
Double mlastlocationlat,mlastlocationlong,mcurrentlocationlat,mcurrentlocationlong;
SharedPreferences sharedPreferences,startdistance_preference;
SharedPreferences.Editor editor;
float f_TotDist ;
int timercount;
Database database;
private static final String TAG = LocationUpdatesService.class.getSimpleName();
/**
* The name of the channel for notifications.
*/
private static final String CHANNEL_ID = "channel_01";
static final String ACTION_BROADCAST = PACKAGE_NAME + ".broadcast";
static final String EXTRA_LOCATION = PACKAGE_NAME + ".location";
private static final String EXTRA_STARTED_FROM_NOTIFICATION = PACKAGE_NAME +
".started_from_notification";
private final IBinder mBinder = new LocalBinder();
/**
* The desired interval for location updates. Inexact. Updates may be more or less frequent.
*/
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
/**
* The fastest rate for active location updates. Updates will never be more frequent
* than this value.
*/
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS;
/**
* The identifier for the notification displayed for the foreground service.
*/
private static final int NOTIFICATION_ID = 12345678;
/**
* Used to check whether the bound activity has really gone away and not unbound as part of an
* orientation change. We create a foreground service notification only if the former takes
* place.
*/
private boolean mChangingConfiguration = false;
private NotificationManager mNotificationManager;
/**
* Contains parameters used by {@link com.google.android.gms.location.FusedLocationProviderApi}.
*/
private LocationRequest mLocationRequest;
/**
* Provides access to the Fused Location Provider API.
*/
private FusedLocationProviderClient mFusedLocationClient;
/**
* Callback for changes in location.
*/
private LocationCallback mLocationCallback;
private Handler mServiceHandler;
/**
* The current location.
*/
private Location mLocation;
public LocationUpdatesService() {
}
@Override
public void onCreate() {
Log.i("PL", "Service oncreated");
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Log.i("PL", "onLocationResult");
onNewLocation(locationResult.getLastLocation());
}
};
createLocationRequest();
getLastLocation();
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
mServiceHandler = new Handler(handlerThread.getLooper());
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Android O requires a Notification Channel.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.app_name);
// Create the channel for the notification
NotificationChannel mChannel =
new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT);
// Set the Notification Channel for the Notification Manager.
mNotificationManager.createNotificationChannel(mChannel);
}
database=new Database(this);
// this.deleteDatabase("EmployeeDatabase.db");
database.getWritableDatabase();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("PL", "Service startedcommand");
// Tells the system to not try to recreate the service after it has been killed.
return START_STICKY;
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mChangingConfiguration = true;
Log.i("PL", "onConfigurationChanged");
}
@Override
public IBinder onBind(Intent intent) {
// Called when a client (MainActivity in case of this sample) comes to the foreground
// and binds with this service. The service should cease to be a foreground service
// when that happens.
Log.i("PL", "in onBind()");
stopForeground(true);
mChangingConfiguration = false;
return mBinder;
}
@Override
public void onRebind(Intent intent) {
// Called when a client (MainActivity in case of this sample) returns to the foreground
// and binds once again with this service. The service should cease to be a foreground
// service when that happens.
Log.i("PL", "in onRebind()");
stopForeground(true);
mChangingConfiguration = false;
super.onRebind(intent);
}
@Override
public boolean onUnbind(Intent intent) {
Log.i("PL", "unbind--Last client unbound from service");
// Called when the last client (MainActivity in case of this sample) unbinds from this
// service. If this method is called due to a configuration change in MainActivity, we
// do nothing. Otherwise, we make this service a foreground service.
if (!mChangingConfiguration && Utils.requestingLocationUpdates(this)) {
Log.i("PL", "unbind--Starting foreground service");
startForeground(NOTIFICATION_ID, getNotification());
}
return true; // Ensures onRebind() is called when a client re-binds.
}
@Override
public void onDestroy() {
mServiceHandler.removeCallbacksAndMessages(null);
}
/**
* Makes a request for location updates. Note that in this sample we merely log the
* {@link SecurityException}.
*/
public void requestLocationUpdates() {
Log.i("PL", "Requesting location updates");
Utils.setRequestingLocationUpdates(this, true);
startService(new Intent(getApplicationContext(), LocationUpdatesService.class));
try {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
} catch (SecurityException unlikely) {
Utils.setRequestingLocationUpdates(this, false);
Log.e("PL", "Lost location permission. Could not request updates. " + unlikely);
}
}
/**
* Removes location updates. Note that in this sample we merely log the
* {@link SecurityException}.
*/
public void removeLocationUpdates() {
Log.i("PL", "Removing location updates");
try {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
Utils.setRequestingLocationUpdates(this, false);
stopSelf();
} catch (SecurityException unlikely) {
Utils.setRequestingLocationUpdates(this, true);
Log.e("PL", "Lost location permission. Could not remove updates. " + unlikely);
}
}
/**
* Returns the {@link NotificationCompat} used as part of the foreground service.
*/
private Notification getNotification() {
Intent intent = new Intent(this, LocationUpdatesService.class);
Log.i("PL", "getNotification");
CharSequence text = Utils.getLocationText(mLocation,f_TotDist);
// Extra to help us figure out if we arrived in onStartCommand via the notification or not.
intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true);
// The PendingIntent that leads to a call to onStartCommand() in this service.
PendingIntent servicePendingIntent = PendingIntent.getService(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// The PendingIntent to launch activity.
PendingIntent activityPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentText(text)
.setContentTitle(Utils.getLocationTitle(this))
.setOngoing(true)
.setPriority(Notification.PRIORITY_HIGH)
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker(text)
.setWhen(System.currentTimeMillis());
Notification notification = null;
// Set the Channel ID for Android O.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// builder.setChannelId(CHANNEL_ID); // Channel ID
// Create a notification and set the notification channel.
notification = new Notification.Builder(this)
.setChannelId(CHANNEL_ID)
.setContentText(text)
.setContentTitle(Utils.getLocationTitle(this))
.setOngoing(true)
.setPriority(Notification.PRIORITY_HIGH)
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker(text)
.build();
}
else
{
}
return builder.build();
}
private void getLastLocation() {
try {
mFusedLocationClient.getLastLocation()
.addOnCompleteListener(new OnCompleteListener<Location>() {
@Override
public void onComplete(@NonNull Task<Location> task) {
if (task.isSuccessful() && task.getResult() != null) {
mLocation = task.getResult();
Log.w("PL", "mLocation lastknow.");
} else {
Log.w("PL", "Failed to get location.");
}
}
});
} catch (SecurityException unlikely) {
Log.e("PL", "Lost location permission." + unlikely);
}
}
private void onNewLocation(Location location) {
Log.i("PL", "New location: " + location);
mLocation = location;
startdistance_preference = getSharedPreferences("startLessonPref",
Context.MODE_PRIVATE);
sharedPreferences = getSharedPreferences("myprefer", MODE_PRIVATE);
editor = sharedPreferences.edit();
editor.putString("dest_Lat", String.valueOf(location.getLatitude()));
editor.putString("dest_Long", String.valueOf(location.getLongitude()));
editor.putString("Lat", String.valueOf(location.getLatitude()));
editor.putString("Long", String.valueOf(location.getLongitude()));
if(mlastlocationlat==null && mlastlocationlong==null && mcurrentlocationlat==null && mcurrentlocationlong==null)
{
editor.putString("mlastlocationlat", String.valueOf(location.getLatitude()));
editor.putString("mlastlocationlong", String.valueOf(location.getLongitude()));
editor.putString("mcurrentlocationlat", String.valueOf(location.getLatitude()));
editor.putString("mcurrentlocationlong", String.valueOf(location.getLongitude()));
mlastlocationlat=location.getLatitude();
mlastlocationlong=location.getLongitude();
mcurrentlocationlat=location.getLatitude();
mcurrentlocationlong=location.getLongitude();
Log.e("RS","mlastlocationlat" + mlastlocationlat);
Log.e("RS","mlastlocationlong" + mlastlocationlong);
Log.e("RS","mcurrentlocationlat" + mcurrentlocationlat);
Log.e("RS","mcurrentlocationlong" + mcurrentlocationlong);
}
else
{
mlastlocationlat=mcurrentlocationlat;
mlastlocationlong=mcurrentlocationlong;
mcurrentlocationlat=location.getLatitude();
mcurrentlocationlong=location.getLongitude();
editor.putString("mlastlocationlat", String.valueOf(mcurrentlocationlat));
editor.putString("mlastlocationlong", String.valueOf(mcurrentlocationlong));
editor.putString("mcurrentlocationlat", String.valueOf(location.getLatitude()));
editor.putString("mcurrentlocationlong", String.valueOf(location.getLongitude()));
/* mcurrentlocationlat=Double.valueOf(String.format("%.4f", location.getLatitude()));
mcurrentlocationlong=Double.valueOf(String.format("%.4f", location.getLongitude()));
*/ Log.e("RS","else--mlastlocationlat" + mlastlocationlat);
Log.e("RS","else-mlastlocationlong" + mlastlocationlong);
Log.e("RS","else-mcurrentlocationlat--" + mcurrentlocationlat);
Log.e("RS","else-mcurrentlocationlong--" + mcurrentlocationlong);
}
editor.commit();
Float dist = distanceCal(mlastlocationlat, mlastlocationlong,mcurrentlocationlat, mcurrentlocationlong);
// Notify anyone listening for broadcasts about the new location.
Intent intent = new Intent(ACTION_BROADCAST);
intent.putExtra(EXTRA_LOCATION, location);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
// Update notification content if running as a foreground service.
if (serviceIsRunningInForeground(this)) {
mNotificationManager.notify(NOTIFICATION_ID, getNotification());
}
}
/**
* Sets the location request parameters.
*/
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setSmallestDisplacement(0);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/**
* Class used for the client Binder. Since this service runs in the same process as its
* clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocationUpdatesService getService() {
return LocationUpdatesService.this;
}
}
/**
* Returns true if this is a foreground service.
*
* @param context The {@link Context}.
*/
public boolean serviceIsRunningInForeground(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
Integer.MAX_VALUE)) {
if (getClass().getName().equals(service.service.getClassName())) {
if (service.foreground) {
Log.i("PL", "if--serviceisruningforegroun"+service.foreground);
return true;
}
else
{
Log.i("PL", "elsee--serviceisruningforegroun"+service.foreground);
}
}
else {
//Log.i("PL", "elsee-main-serviceisruningforegroun"+service.foreground);
}
}
return false;
}
private float distanceCal(double lat1, double lon1, double lat2, double lon2) {
Location loc1 = new Location("");
loc1.setLatitude(lat1);
loc1.setLongitude(lon1);
Location loc2 = new Location("");
loc2.setLatitude(lat2);
loc2.setLongitude(lon2);
float distanceInMeters = loc1.distanceTo(loc2);
float distanceinmeter= Float.parseFloat(String.format("%.2f", distanceInMeters));
Log.e("RS--first--","-distanceInMeters-" +distanceInMeters);
Log.e("RS---#####-1-" + lat1, "--" + lon1);
Log.e("RS---#####-2-" + lat2, "--" + lon2);
startdistance_preference = getSharedPreferences("startLessonPref",
Context.MODE_PRIVATE);
f_TotDist = startdistance_preference.getFloat("str_TotalDist", 0);
Log.e("RS","-f_TotDist-first-" +f_TotDist);
timercount = Integer.parseInt(startdistance_preference.getString("timerstart", null));
database.insertData(String.valueOf(timercount),mcurrentlocationlat,mcurrentlocationlong,f_TotDist);
// startLesson_preference = getSharedPreferences("startLessonPref", Context.MODE_PRIVATE);
f_TotDist+=(distanceinmeter);
timercount=timercount+3;
Log.e("RS","-f_TotDist--if-" +f_TotDist);
SharedPreferences.Editor editor1 = startdistance_preference.edit();
editor1.putFloat("str_TotalDist", (float) f_TotDist);
editor1.putString("timerstart", String.valueOf(timercount));
editor1.commit();
return distanceInMeters;
}
}
Активность:
public class MainActivity extends AppCompatActivity
SharedPreferences startdistance_preference;
ArrayList arrayList;
Timer timer,timer1;
private static final String TAG = MainActivity.class.getSimpleName();
// Used in checking for runtime permissions.
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
// The BroadcastReceiver used to listen from broadcasts from the service.
private MyReceiver myReceiver;
ListView listView;
// A reference to the service used to get location updates.
private LocationUpdatesService mService = null;
Database database;
// Tracks the bound state of the service.
private boolean mBound = false;
// UI elements.
private Button mRequestLocationUpdatesButton;
private Button mRemoveLocationUpdatesButton;
// Monitors the state of the connection to the service.
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocationUpdatesService.LocalBinder binder = (LocationUpdatesService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
mBound = false;
}
};
TextView total_distance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myReceiver = new MyReceiver();
setContentView(R.layout.back_services);
database=new Database(this);
// this.deleteDatabase("EmployeeDatabase.db");
database.getWritableDatabase();
total_distance=(TextView)findViewById(R.id.total_distance);
listView=(ListView)findViewById(R.id.listView);
// schedule the task to RUN every hour
timer = new Timer();
TimerTask hourlyTask = new TimerTask() {
@Override
public void run() {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
// check if GPS enabled
startdistance_preference = getSharedPreferences("startLessonPref", Context.MODE_PRIVATE);
String stringLatitude1 = startdistance_preference.getString("mlastlocationlat", null);
String stringLongitude1 = startdistance_preference.getString("mlastlocationlong", null);
// String totaldistance = startdistance_preference.getString("str_TotalDist", null);
float f_TotDist = startdistance_preference.getFloat("str_TotalDist", 0);
Log.e("RS","-runnin--f_TotDist-first-" +f_TotDist);
total_distance.setText("Total Distance-"+f_TotDist/1000 + " km");
//Log.e("RS","running---stringLatitude1-----" + stringLatitude1);
Toast.makeText(MainActivity.this, "distance-**-" + f_TotDist , Toast.LENGTH_LONG).show();
if(database.fetchData()!=null) {
arrayList = database.fetchData();
Log.e("RS","---arrayList-----" + arrayList);
DistanceAdap adapter = new DistanceAdap(getApplicationContext(), android.R.layout.activity_list_item, android.R.id.text1, arrayList);
listView.setAdapter(adapter);
}
}
});
}
};
timer.schedule(hourlyTask, 0l, 1000 * 1 * 10);
startdistance_preference = getSharedPreferences("startLessonPref", Context.MODE_PRIVATE);
}
@Override
protected void onStart() {
super.onStart();
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener(this);
mRequestLocationUpdatesButton = (Button) findViewById(R.id.request_location_updates_button);
mRemoveLocationUpdatesButton = (Button) findViewById(R.id.remove_location_updates_button);
mRequestLocationUpdatesButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startdistance_preference = getSharedPreferences("startLessonPref",
Context.MODE_PRIVATE);
SharedPreferences.Editor editor1 = startdistance_preference.edit();
editor1.putFloat("str_TotalDist", (float) 0.0);
editor1.putString("timerstart", "0");
editor1.commit();
if (!checkPermissions()) {
requestPermissions();
} else {
mService.requestLocationUpdates();
}
}
});
mRemoveLocationUpdatesButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startdistance_preference = getSharedPreferences("startLessonPref", Context.MODE_PRIVATE);
float f_TotDist = startdistance_preference.getFloat("str_TotalDist", 0);
Log.e("RS","-runnin--f_TotDist-first-" +f_TotDist);
total_distance.setText("Total distance"+f_TotDist/ 1000+"km");
mService.removeLocationUpdates();
}
});
// Restore the state of the buttons when the activity (re)launches.
setButtonsState(Utils.requestingLocationUpdates(this));
// Bind to the service. If the service is in foreground mode, this signals to the service
// that since this activity is in the foreground, the service can exit foreground mode.
bindService(new Intent(this, LocationUpdatesService.class), mServiceConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
if (mBound) {
// Unbind from the service. This signals to the service that this activity is no longer
// in the foreground, and the service can respond by promoting itself to a foreground
// service.
unbindService(mServiceConnection);
mBound = false;
}
PreferenceManager.getDefaultSharedPreferences(this)
.unregisterOnSharedPreferenceChangeListener(this);
super.onStop();
}
private void setButtonsState(boolean requestingLocationUpdates) {
if (requestingLocationUpdates) {
mRequestLocationUpdatesButton.setEnabled(false);
mRemoveLocationUpdatesButton.setEnabled(true);
} else {
mRequestLocationUpdatesButton.setEnabled(true);
mRemoveLocationUpdatesButton.setEnabled(false);
}
}
}
Примечание.уведомление означает, что когда приложение очищается из стека, местоположение обновляется не во всех версиях. Я хочу рассчитать расстояние для каждых 2 минут
https://github.com/googlesamples/android-play-location/tree/master/LocationUpdatesForegroundService/app/src/main/java/com/google/android/gms/location/sample/locationupdatesforegroundservice