当应用程序从牛轧糖(版本 25)事件中的后台清除时,服务未运行 我使用了启动通知



因为我想使用服务中的googleapiclient位置计算每两分钟的距离。

在版本 25 中(从缓存中清除应用程序时牛轧糖服务不起作用(

我在活动中启动了该服务,并在启动命令中给出了start_sticky,没有通知,它也应该工作吗? 低于奥利奥版本。

对于奥利奥版本,我添加了startforeground通知,因此即使在奥利奥版本中工作 - 即使应用程序从后台清除,但在牛轧糖中,当我从后台清除应用程序时,相同的代码在通知或不通知的情况下都不起作用未运行。请帮助我。

低于版本>25 在没有通知的情况下工作,当应用程序也从缓存中清除时,服务正在运行。但是在版本 25 中,我不知道为什么在清除表单缓存时服务不运行。请有人帮助我。

服务代码:

public class ForegroundLocationService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
Double mlastlocationlat,mlastlocationlong,mcurrentlocationlat,mcurrentlocationlong;
SharedPreferences sharedPreferences,startdistance_preference;
SharedPreferences.Editor editor;
float f_TotDist ;
int timercount;
Database database;
private static final String TAG = ForegroundLocationService.class.getSimpleName();
// the notification id for the foreground notification
public static final int GPS_NOTIFICATION = 1;
// the interval in seconds that gps updates are requested
private static final int UPDATE_INTERVAL_IN_SECONDS = 15;
// is this service currently running in the foreground?
private boolean isForeground = false;
// the google api client
private GoogleApiClient googleApiClient;
// the wakelock used to keep the app alive while the screen is off
private PowerManager.WakeLock wakeLock;
@Override
public void onCreate() {
super.onCreate();
Log.i("KS", "oncreate " );
// create google api client
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
// get a wakelock from the power manager
final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
Log.i("KS", "oncreate wakeLock"+wakeLock );
database=new Database(this);
// this.deleteDatabase("EmployeeDatabase.db");
database.getWritableDatabase();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("KS", "onstartcommand " );
if (!isForeground) {
Log.i("KS", "Starting the isForeground" + isForeground);
startForeground(ForegroundLocationService.GPS_NOTIFICATION,
notifyUserThatLocationServiceStarted());
isForeground = true;
Utils.setRequestingLocationUpdates(this, true);
// connect to google api client
googleApiClient.connect();
// acquire wakelock
wakeLock.acquire();
}
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
Log.i("KS", "ondestroy the " + this.getClass().getSimpleName());
stopForeground(true);
isForeground = false;
// disconnect from google api client
googleApiClient.disconnect();
Utils.setRequestingLocationUpdates(this, false);
// release wakelock if it is held
if (null != wakeLock && wakeLock.isHeld()) {
Log.i("KS", "if destroy" + wakeLock);
wakeLock.release();
}
super.onDestroy();
}
private LocationRequest getLocationRequest() {
Log.i("KS", "getLocationRequest " );
LocationRequest locationRequest = LocationRequest.create();
// we always want the highest accuracy
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// we want to make sure that we get an updated location at the specified interval
locationRequest.setInterval(5000);
locationRequest.setSmallestDisplacement(0);
// this sets the fastest interval that the app can receive updates from other apps accessing
// the location service. for example, if Google Maps is running in the background
// we can update our location from what it sees every five seconds
locationRequest.setFastestInterval(5000);
locationRequest.setMaxWaitTime(TimeUnit.SECONDS.toMillis(UPDATE_INTERVAL_IN_SECONDS));
return locationRequest;
}
private Notification notifyUserThatLocationServiceStarted() {
Log.i("KS", "notifyUserThatLocationServiceStarted " );
// pop up a notification that the location service is running
Intent notificationIntent = new Intent(this, NotificationActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
final Notification.Builder builder = new Notification.Builder(this)
.setSmallIcon(R.drawable.getspot_logo)
.setContentTitle(getString(R.string.foreground_location_service))
.setContentText(getString(R.string.service_is_running))
.setWhen(System.currentTimeMillis());
final Notification notification;
String CHANNEL_ID = "channel_01";
Notification notification1= 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.
notification1 = new Notification.Builder(this)
.setChannelId(CHANNEL_ID)
.setContentTitle(getString(R.string.foreground_location_service))
.setContentText(getString(R.string.service_is_running))
.setOngoing(true)
.setPriority(Notification.PRIORITY_HIGH)
.setSmallIcon(R.mipmap.ic_launcher)

.build();
notification=notification1;
}
else
{
notification=builder.build();;
}

return notification;
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.i("KS", "onConnected " );
try {
// request location updates from the fused location provider
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, getLocationRequest(), this);
} catch (SecurityException securityException) {
Log.e(TAG, "Exception while requesting location updates", securityException);
}
}
@Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Google API Client suspended.");
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.e(TAG, "Failed to connect to Google API Client.");
}
@Override
public void onLocationChanged(Location location) {
Log.i("KS", "onLocationChanged: " + location.toString());
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()));
Log.e("RS","shared--" + sharedPreferences.getString("mlastlocationlat", null));

if(sharedPreferences.getString("mlastlocationlat", null)==null && sharedPreferences.getString("mlastlocationlong", null)==null && sharedPreferences.getString("mcurrentlocationlat", null)==null && sharedPreferences.getString("mcurrentlocationlong", null)==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= Double.valueOf(sharedPreferences.getString("mcurrentlocationlat", null));
mlastlocationlong=Double.valueOf(sharedPreferences.getString("mcurrentlocationlong", null));
;
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);
}
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 SampleBackgroundServices extends AppCompatActivity implements
SharedPreferences.OnSharedPreferenceChangeListener {

// the identifier for the permissions request
private static final int PERMISSION_REQUEST_ID = 1999;
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;
SharedPreferences sharedPreferences;
SharedPreferences.Editor editor;
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;
TextView total_distance;
// UI elements.
private Button mRequestLocationUpdatesButton;
private Button mRemoveLocationUpdatesButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.back_services);
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) {
startService(new Intent(getApplicationContext(), ForegroundLocationService.class));
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();

sharedPreferences = getSharedPreferences("myprefer", MODE_PRIVATE);
editor = sharedPreferences.edit();

editor.putString("mcurrentlocationlong", null);
editor.putString("mcurrentlocationlat", null);
editor.putString("mlastlocationlat", null);
editor.putString("mlastlocationlong", null);
editor.commit();

}
});
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");
stopService(new Intent(getApplicationContext(), ForegroundLocationService.class));

}
});

}
@Override
public void onResume() {

super.onResume();
}

}

注意:我不知道如何在牛轧糖中解决这个问题,请给我解决方案。奥利奥版本只会停止,所以我们使用通知,在牛轧糖现在也有问题。

清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.getspot.getspot">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:hardwareAccelerated="false"
android:icon="@drawable/getspot_logo"
android:label="@string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".activities.SplashScreen"
android:screenOrientation="portrait"
android:configChanges="keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".background_services.ForegroundLocationService"
android:enabled="true" />

</application>
</manifest>

在 Android7.0 (API 级别 25(、Android 8.0 (API 级别 26( 后台服务和执行 安卓限制。由于应用程序在后台运行,它会消耗设备的一些有限资源,例如 RAM。更多详情

迁移指南

默认情况下,这些更改仅影响以 Android 8.0(API 级别 26(或更高版本为目标平台的应用。但是,用户可以从"设置"屏幕为任何应用启用这些限制,即使该应用的目标 API 级别低于 26。您可能需要更新应用以符合新的限制。

查看应用如何使用服务。如果你的应用依赖于在应用处于空闲状态时在后台运行的服务,则需要替换它们。可能的解决方案包括:

如果应用需要在应用处于后台时创建前台服务,请使用startForegroundService((方法而不是startService((。如果用户注意到该服务,请将其设置为前台服务。例如,播放音频的服务应始终是前台服务。使用startForegroundService(( 方法而不是startService((创建服务。 找到一种使用计划作业复制服务功能的方法。如果服务没有执行用户立即注意到的操作,则通常应该能够改用计划作业。 使用 FCM 在发生网络事件时有选择地唤醒应用程序,而不是在后台轮询。 推迟后台工作,直到应用程序自然出现在前台。 查看应用清单中定义的广播接收器。如果清单声明了隐式广播的接收器,则必须替换它。可能的解决方案包括:

在运行时通过调用Context.registerReceiver((创建接收器,而不是在清单中声明接收器。 使用计划作业检查触发隐式广播的条件。

最新更新