问题
I have tried every suggestion I could find on the Internet to use Foreground Service to keep my app running beyond sleep and deep sleep modes but nothing has been successful so far.
I am working on a taxi booking application. I designed it to start emitting driver's location to server whenever the driver turns himself Online and stop emitting when Offline.
The following is the Foreground Service code that is started whenever driver turns himself Online and stopped when he presses online button which changes Common.CustomSocketOn to 0.
It work fine during screen wake and also works when the screen is off before the app gets killed.
However, even with WAKE_LOCK acquired, it still can't stay more than few minutes in sleep mode before getting killed by Android 7.
This failure to keep running in sleep mode breaks down many other features of the app because when the app gets killed silently, it does not get the chance to turn the driver Offline nor sign him out. As a result, the driver gets booking requests when his app is not running and therefore, cannot attend to it, and that keeps the booking from going to the next available driver. In fact, this causes so many other anomalies.
Please, can somebody tell me any other thing I need to do to keep Android from killing the Foreground Service.
public class OnlineForeGroundService extends Service {
private static final String TAG_FOREGROUND_SERVICE = "FOREGROUND_SERVICE";
public static final String ACTION_START_FOREGROUND_SERVICE = "ACTION_START_FOREGROUND_SERVICE";
public static final String ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE";
private static LocationListener locationListener;
private static LocationManager locationManager;
private PowerManager.WakeLock wakeLock;
public OnlineForeGroundService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
//throw new UnsupportedOperationException("Not yet implemented");
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG_FOREGROUND_SERVICE, "My foreground service.");
final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
try {
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "KEEP_AWAKE");
}
catch (Exception e){
e.printStackTrace();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null)
{
String action = intent.getAction();
if(action != null) {
switch (action) {
case ACTION_START_FOREGROUND_SERVICE:
startForegroundService();
Toast.makeText(getApplicationContext(), getText(R.string.going_online), Toast.LENGTH_SHORT).show();
wakeLock.acquire();
break;
case ACTION_STOP_FOREGROUND_SERVICE:
stopForegroundService();
//Toast.makeText(getApplicationContext(), getText(R.string.going_offline), Toast.LENGTH_SHORT).show();
break;
}
}
}
return super.onStartCommand(intent, flags, startId);
//return START_STICKY;
}
/* Used to build and start foreground service. */
@SuppressLint("MissingPermission")
private void startForegroundService()
{
if(OnlineForeGroundService.locationManager == null) {
OnlineForeGroundService.locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
if(OnlineForeGroundService.locationListener == null) {
OnlineForeGroundService.locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if (Common.CustomSocketOn == 1) {
SharedPreferences userPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (Common.OldLatitude != 0 && Common.OldLongitude != 0) {
float distance[] = new float[1];
Location.distanceBetween(Common.OldLatitude, Common.OldLongitude, location.getLatitude(), location.getLongitude(), distance);
//Distance - 100
if (distance.length > 0 && distance[0] > 30) {
try {
JSONArray locAry = new JSONArray();
locAry.put(location.getLatitude());
locAry.put(location.getLongitude());
JSONObject emitobj = new JSONObject();
emitobj.put("coords", locAry);
emitobj.put("driver_name", userPref.getString("user_name", ""));
emitobj.put("driver_id", userPref.getString("id", ""));
emitobj.put("driver_status", "1"); //change by sir
emitobj.put("car_type", userPref.getString("car_type", ""));
emitobj.put("isdevice", "1");
emitobj.put("booking_status", userPref.getString("booking_status", ""));
emitobj.put("isLocationChange", 1);
if (location.getLatitude() != 0.0 && location.getLongitude() != 0.0 && Common.socket != null && Common.socket.connected()) {
Common.socket.emit("Create Driver Data", emitobj);
} else if (location.getLatitude() != 0.0 && location.getLongitude() != 0.0 && Common.socket == null) {
Common.socket = null;
SocketSingleObject.instance = null;
Common.socket = SocketSingleObject.get(getApplicationContext()).getSocket();
Common.socket.connect();
Common.socket.emit("Create Driver Data", emitobj);
} else if (location.getLatitude() != 0.0 && location.getLongitude() != 0.0 && Common.socket != null && !Common.socket.connected()) {
Common.socket.connect();
Common.socket.emit("Create Driver Data", emitobj);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Common.OldLatitude = location.getLatitude();
Common.OldLongitude = location.getLongitude();
}
}
if (Common.OldLatitude == 0 && Common.OldLongitude == 0) {
Common.OldLatitude = location.getLatitude();
Common.OldLongitude = location.getLongitude();
}
}
else{
stopForegroundService();
}
}
@Override
public void onProviderDisabled(String provider) {
Log.d("Latitude", "disable");
}
@Override
public void onProviderEnabled(String provider) {
Log.d("Latitude", "enable");
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
}
if(Common.isPermission){
if(Common.CustomSocketOn == 1){
try {
OnlineForeGroundService.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, Common.DriverDistanceTime, Common.DriverDistance, OnlineForeGroundService.locationListener);
OnlineForeGroundService.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, Common.DriverDistanceTime, Common.DriverDistance, OnlineForeGroundService.locationListener);
}
catch (Exception e){
e.printStackTrace();
}
}
}
Log.d(TAG_FOREGROUND_SERVICE, "Starting foreground service.");
String onlineSticker = getText(R.string.app_name)+" - Online";
Intent notificationIntent = new Intent(this, HomeActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification;
/*if(android.os.Build.VERSION.SDK_INT >= 26) {
notification = new Notification.Builder(HomeActivity.class, NotificationManager.IMPORTANCE_HIGH)
.setContentTitle(getText(R.string.app_name))
.setContentText(getText(R.string.you_are_online))
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setTicker(onlineSticker)
.build();
//startForeground(ONGOING_NOTIFICATION_ID, notification);
// Start foreground service.
}
else{*/
notification = new Notification.Builder(this)
.setContentTitle(getText(R.string.app_name))
.setContentText(getText(R.string.you_are_online))
.setPriority(Notification.PRIORITY_HIGH)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setTicker(onlineSticker)
.build();
//}
startForeground(397, notification);
}
private void stopForegroundService()
{
Toast.makeText(getApplicationContext(), getText(R.string.going_offline), Toast.LENGTH_SHORT).show();
if(Common.isPermission){
if(Common.CustomSocketOn == 0){
try {
OnlineForeGroundService.locationManager.removeUpdates(OnlineForeGroundService.locationListener);
//OnlineForeGroundService.locationListener = null;
}
catch (Exception e){
e.printStackTrace();
}
}
}
Log.d(TAG_FOREGROUND_SERVICE, "Stop foreground service.");
if (null != wakeLock && wakeLock.isHeld()) {
wakeLock.release();
}
// Stop foreground service and remove the notification.
stopForeground(true);
// Stop the foreground service.
stopSelf();
}
}
Here is the androidManifest entry for the service and WAKE_LOCK permission:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<service
android:name=".driver.service.OnlineForeGroundService"
android:process=".process"
android:enabled="true"
android:exported="true" ></service>
回答1:
Check how you are starting your OnlineForeGroundService
.
On Android Oreo and above it needs to be started with startForegroundService(Intent intent)
, not startService(Intent intent)
For example something like:
final Intent serviceIntent = new Intent(context, OnlineForeGroundService.class);
serviceIntent.setAction(OnlineForeGroundService.ACTION_START_FOREGROUND_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent);
} else {
startService(serviceIntent);
}
回答2:
Please see this excellent site which provides a vast amount of information covering various different handset vendors and Android API versions.
This has helped me massively understand the very common Android developer problem of dealing with reports and feedback of foreground services being killed despite following the documented steps to ensure your service is setup correctly to avoid being shutdown.
https://dontkillmyapp.com/stock_android
The site includes mention of the Dianne Hackborn comments which are now no longer accessible on the Google plus (due to it's end of life).
Ultimately it seems that the solution to prevent your Foreground Service from being shutdown may vary across Android OS version and device manufacturer, but this site provides a good summary of the steps users can be directed to follow and also developers can implement (where possible) to try and mitigate this issue.
来源:https://stackoverflow.com/questions/52417086/android-7-0-kills-app-even-when-foreground-service-is-running