android - Oreo+ 中位置更新的前台服务不起作用
问题描述
我的应用程序要求定期跟踪用户。这是我的位置服务类,旨在在设定的时间间隔内提供位置更新。这段代码在 Nougat 之前工作正常,但在 Oreo 上不起作用。几天前这段代码运行良好,不知道出了什么问题。欢迎提出建议和评论。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
startMyOwnForeground();
else{
startForeground(1, createNotification());}
getLocationUpdates();
thread = new LocationMonitoringThread();
thread.start();
mLocationCallback = new LocationCallback(){
@Override
public void onLocationResult(LocationResult locationResult) {
sendNewLocationBroadcast(locationResult);
}
};
return START_STICKY;
}
private void startMyOwnForeground() {
String CHANNEL_ID = "my_channel_01";
CharSequence name = "Project U";
String Description = "You are being Monitored";
int NOTIFICATION_ID = 234;
NotificationManager notificationManager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >=
android.os.Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID,
name, importance);
mChannel.setDescription(Description);
mChannel.setVibrationPattern(new long[]{ 0 });
mChannel.enableVibration(true);
if (notificationManager != null) {
notificationManager.createNotificationChannel(mChannel);
}
}
NotificationCompat.Builder builder = new
NotificationCompat.Builder(this, CHANNEL_ID)
.setContentText("You Are being Monitored")
.setSmallIcon(R.drawable.ic_baseline_satellite_24px)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true);
builder.setOngoing(true);
if (notificationManager != null) {
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
}
private void getLocationUpdates() {
mLocationProviderClient =
LocationServices.getFusedLocationProviderClient(this);
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(900000);
mLocationRequest.setFastestInterval(20000);
}
private void sendNewLocationBroadcast(LocationResult result){
Log.i(TAG, "sendNewLocationBroadcast: ");
Intent intent = new Intent("com.example.projectu.LocationService");
double latitude = result.getLastLocation().getLatitude();
double longtitude = result.getLastLocation().getLongitude();
int complete = 1;
Log.d(TAG, "date: " + latitude);
Log.d(TAG, "date: " + longtitude);
intent.putExtra("latitude", latitude);
intent.putExtra("longtitude", longtitude);
intent.putExtra("complete", complete);
sendBroadcast(intent);
FirebaseApp.initializeApp(this);
if (FirebaseAuth.getInstance().getCurrentUser() != null) {
uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
}
adb = FirebaseFirestore.getInstance();
Map<String, Object> att = new HashMap<>();
att.put("Location", (new GeoPoint(latitude, longtitude)));
att.put("latestUpdateTimestamp", FieldValue.serverTimestamp());
adb.collection("Users").document(uid + "")
.update(att);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private Notification createNotification(){
String CHANNEL_ID = "my_channel_01";
NotificationCompat.Builder builder = new
NotificationCompat.Builder(this,
CHANNEL_ID)
.setSmallIcon(R.drawable.ic_baseline_satellite_24px)
.setContentTitle("Project U")
.setContentText("You are being Monitored")
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
builder.setOngoing(true);
return builder.build();
}
class LocationMonitoringThread extends Thread{
Looper looper;
@Override
public void run() {
if (ActivityCompat.checkSelfPermission(LocationService.this,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
return;
}
getLocationUpdates();
looper = Looper.myLooper();
looper.prepare();
mLocationProviderClient.requestLocationUpdates(
mLocationRequest,
mLocationCallback,
looper
);
looper.loop();
}
}
}
解决方案
以下是 Android >= O 中前台服务的两个常见缺陷:
1.您是否申请了前台服务权限?见这里:
注意:面向 Android 9(API 级别 28)或更高版本并使用前台服务的应用必须请求 FOREGROUND_SERVICE 权限。这是一个正常的权限,因此系统会自动将其授予请求的应用程序。
如果针对 API 级别 28 或更高级别的应用尝试创建前台服务而不请求 FOREGROUND_SERVICE,则系统会引发 SecurityException。
2.您是否使用 启动服务Context.startForegroundService()
?
如果应用需要创建前台服务,应用应该调用 startForegroundService()。该方法创建了一个后台服务,但该方法向系统发出信号,该服务将把自己提升到前台。创建服务后,服务必须在五秒内调用其 startForeground() 方法。
我的一个项目中的示例代码,以确保调用正确的方法来启动服务:
Intent i = new Intent(context, MyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(i);
} else {
context.startService(i);
}
推荐阅读
- reactjs - Сannot 在测试中设置属性
- c++ - 从指针复制对象
- android - 如何使用 adb 卸载 Google Play 商店
- c++ - 默认情况下是通过引用或值传递的对象
- vue.js - 从 vuex 存储“发送”数据到组件
- html - XML 文件仅显示具有 DTD 而非 XSLT 的数据
- java - 等于和包含有什么区别
- quantum-computing - 你能在量子计算机上运行 64 位应用程序吗?
- ios - 正确的对象和语法将杂项元数据传递给 Swift 中的另一个方法
- gitlab-ci - gitlab-ci 缓存如何在 docker runner 上运行?/cache 目录是什么?什么是cache_dir?