Oreo 上的位置跟踪以及之后使用 IntentService 的位置跟踪
Location tracking on Oreo and later by using an IntentService
我正在开发一个位置跟踪应用程序。我需要每移动 500 米或每 30 分钟获取一次用户位置。我创建了一个前台服务并在 onStartCommand 方法上返回了 START_STICKY。在从最近的应用程序中清除该应用程序之前,跟踪工作正常。如果我从最近的应用程序部分清除了我的应用程序,则前台服务也会从后台删除。我怎样才能让它永远粘在那里?
注意:我在用户知情的情况下进行此位置跟踪
.
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Temp.msg(TAG, "onStartCommand");
startMyOwnForeground();
return START_STICKY;
}
private void startMyOwnForeground() {
String NOTIFICATION_CHANNEL_ID = Temp.getNotificationChannelId();
String channelName = Temp.getNotificationChannelName();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel chan = null;
chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.drawable.ic_push_notifications)
.setContentTitle("Checked In")
.setPriority(NotificationManager.IMPORTANCE_HIGH)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(1, notification);
}
注意:我在 onStartCommand 方法上尝试了 START_STICKY 和 START_NOT_STICKY,但是当应用程序从最近的应用程序中删除时,它都从后台删除了
请尝试这样:
Start Service
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(MainActivity.this, new Intent(MainActivity.this, ServiceLocation.class));
} else {
startService(new Intent(MainActivity.this, ServiceLocation.class));
}
Service Class
public class ServiceLocation extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private static final String NOTIFICATION_CHANNEL_ID = "my_notification_location";
private static final long TIME_INTERVAL_GET_LOCATION = 1000 * 5; // 1 Minute
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 7; // meters
private Handler handlerSendLocation;
private Context mContext;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 5000;
Location locationData;
@Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(TIME_INTERVAL_GET_LOCATION) // 3 seconds, in milliseconds
.setFastestInterval(TIME_INTERVAL_GET_LOCATION); // 1 second, in milliseconds
mContext = this;
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setOngoing(false)
.setSmallIcon(R.drawable.ic_notification)
.setColor(getResources().getColor(R.color.fontColorDarkGray))
.setPriority(Notification.PRIORITY_MIN);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW);
notificationChannel.setDescription(NOTIFICATION_CHANNEL_ID);
notificationChannel.setSound(null, null);
notificationManager.createNotificationChannel(notificationChannel);
startForeground(1, builder.build());
}
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w("Service Update Location", "BGS > Started");
if (handlerSendLocation == null) {
handlerSendLocation = new Handler();
handlerSendLocation.post(runnableSendLocation);
Log.w("Service Send Location", "BGS > handlerSendLocation Initialized");
} else {
Log.w("Service Send Location", "BGS > handlerSendLocation Already Initialized");
}
return START_STICKY;
}
private Runnable runnableSendLocation = new Runnable() {
@Override
public void run() {
Log.w("Service Send Location", "BGS >> Location Updated");
// You can get Location
//locationData and Send Location X Minutes
if (locationData != null) {
Log.w("==>UpdateLocation<==", "" + String.format("%.6f", locationData.getLatitude()) + "," +
String.format("%.6f", locationData.getLongitude()));
}
if (handlerSendLocation != null && runnableSendLocation != null)
handlerSendLocation.postDelayed(runnableSendLocation, TIME_INTERVAL_GET_LOCATION);
}
};
@Override
public void onConnected(@Nullable Bundle bundle) {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
FusedLocationProviderClient mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationClient.requestLocationUpdates(mLocationRequest, new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
locationData = locationResult.getLastLocation();
}
}, null);
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
if (connectionResult.hasResolution() && mContext instanceof Activity) {
try {
Activity activity = (Activity) mContext;
connectionResult.startResolutionForResult(activity, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Log.i("", "Location services connection failed with code " + connectionResult.getErrorCode());
}
}
@Override
public void onLocationChanged(Location location) {
Log.w("==>UpdateLocation<==", "" + String.format("%.6f", location.getLatitude()) + "," + String.format("%.6f", location.getLongitude()));
locationData = location;
}
@Override
public void onDestroy() {
if (handlerSendLocation != null)
handlerSendLocation.removeCallbacks(runnableSendLocation);
Log.w("Service Update Info", "BGS > Stopped");
stopSelf();
super.onDestroy();
}
}
AndroidManifest.XML
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<service
android:name=".ServiceLocation"
android:enabled="true"
android:exported="true" />
我找到应用从后台移除的原因。那不是我的代码的问题。因为我用的phone是红米。在 Redmi phones 中,它需要 Redmi phone 设置的额外权限(AutoStart 权限)。您可以从 Foreground service getting killed from Oreo
获得更多相关信息
我正在开发一个位置跟踪应用程序。我需要每移动 500 米或每 30 分钟获取一次用户位置。我创建了一个前台服务并在 onStartCommand 方法上返回了 START_STICKY。在从最近的应用程序中清除该应用程序之前,跟踪工作正常。如果我从最近的应用程序部分清除了我的应用程序,则前台服务也会从后台删除。我怎样才能让它永远粘在那里?
注意:我在用户知情的情况下进行此位置跟踪 .
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Temp.msg(TAG, "onStartCommand");
startMyOwnForeground();
return START_STICKY;
}
private void startMyOwnForeground() {
String NOTIFICATION_CHANNEL_ID = Temp.getNotificationChannelId();
String channelName = Temp.getNotificationChannelName();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel chan = null;
chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.drawable.ic_push_notifications)
.setContentTitle("Checked In")
.setPriority(NotificationManager.IMPORTANCE_HIGH)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(1, notification);
}
注意:我在 onStartCommand 方法上尝试了 START_STICKY 和 START_NOT_STICKY,但是当应用程序从最近的应用程序中删除时,它都从后台删除了
请尝试这样:
Start Service
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(MainActivity.this, new Intent(MainActivity.this, ServiceLocation.class));
} else {
startService(new Intent(MainActivity.this, ServiceLocation.class));
}
Service Class
public class ServiceLocation extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private static final String NOTIFICATION_CHANNEL_ID = "my_notification_location";
private static final long TIME_INTERVAL_GET_LOCATION = 1000 * 5; // 1 Minute
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 7; // meters
private Handler handlerSendLocation;
private Context mContext;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 5000;
Location locationData;
@Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(TIME_INTERVAL_GET_LOCATION) // 3 seconds, in milliseconds
.setFastestInterval(TIME_INTERVAL_GET_LOCATION); // 1 second, in milliseconds
mContext = this;
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setOngoing(false)
.setSmallIcon(R.drawable.ic_notification)
.setColor(getResources().getColor(R.color.fontColorDarkGray))
.setPriority(Notification.PRIORITY_MIN);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW);
notificationChannel.setDescription(NOTIFICATION_CHANNEL_ID);
notificationChannel.setSound(null, null);
notificationManager.createNotificationChannel(notificationChannel);
startForeground(1, builder.build());
}
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w("Service Update Location", "BGS > Started");
if (handlerSendLocation == null) {
handlerSendLocation = new Handler();
handlerSendLocation.post(runnableSendLocation);
Log.w("Service Send Location", "BGS > handlerSendLocation Initialized");
} else {
Log.w("Service Send Location", "BGS > handlerSendLocation Already Initialized");
}
return START_STICKY;
}
private Runnable runnableSendLocation = new Runnable() {
@Override
public void run() {
Log.w("Service Send Location", "BGS >> Location Updated");
// You can get Location
//locationData and Send Location X Minutes
if (locationData != null) {
Log.w("==>UpdateLocation<==", "" + String.format("%.6f", locationData.getLatitude()) + "," +
String.format("%.6f", locationData.getLongitude()));
}
if (handlerSendLocation != null && runnableSendLocation != null)
handlerSendLocation.postDelayed(runnableSendLocation, TIME_INTERVAL_GET_LOCATION);
}
};
@Override
public void onConnected(@Nullable Bundle bundle) {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
FusedLocationProviderClient mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationClient.requestLocationUpdates(mLocationRequest, new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
locationData = locationResult.getLastLocation();
}
}, null);
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
if (connectionResult.hasResolution() && mContext instanceof Activity) {
try {
Activity activity = (Activity) mContext;
connectionResult.startResolutionForResult(activity, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Log.i("", "Location services connection failed with code " + connectionResult.getErrorCode());
}
}
@Override
public void onLocationChanged(Location location) {
Log.w("==>UpdateLocation<==", "" + String.format("%.6f", location.getLatitude()) + "," + String.format("%.6f", location.getLongitude()));
locationData = location;
}
@Override
public void onDestroy() {
if (handlerSendLocation != null)
handlerSendLocation.removeCallbacks(runnableSendLocation);
Log.w("Service Update Info", "BGS > Stopped");
stopSelf();
super.onDestroy();
}
}
AndroidManifest.XML
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<service
android:name=".ServiceLocation"
android:enabled="true"
android:exported="true" />
我找到应用从后台移除的原因。那不是我的代码的问题。因为我用的phone是红米。在 Redmi phones 中,它需要 Redmi phone 设置的额外权限(AutoStart 权限)。您可以从 Foreground service getting killed from Oreo
获得更多相关信息