[英]No location updates in foreground service Android Q(XIAOMI device) when activity is not visible to user
我正在制作原型应用程序,只有 function 用于从前台服务接收位置更新。 我想我已经阅读了 Stackoverflow 中的所有内容以及有关如何从前台服务获取位置更新的文档。 但是只有在屏幕上可见时,应用程序仍会收到位置更新。 应用程序只有一个带有两个按钮的活动 - 启动和停止服务,以及我显示位置更新的 TextView。 我在清单中有这个权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<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_BACKGROUND_LOCATION" />
这是我在清单中的 LocationService 声明:
<service
android:name=".LocationService"
android:enabled="true"
android:exported="true"
android:foregroundServiceType="location" />
这是我的 LocationService java class 代码:
public class LocationService extends Service implements LocationListener {
private Binder binder;
public LocationUpdateListener getUpdateListener() {
return updateListener;
}
private LocationUpdateListener updateListener;
private LocationManager locationManager;
private String locations = "";
public final static String NOTIFICATION_CHANEL_ID = "LocationServiceChannelRu";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
binder = new Binder();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria locationCriteria = new Criteria();
locationCriteria.setAccuracy(Criteria.NO_REQUIREMENT);
locationCriteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
String provider = locationManager.getBestProvider(locationCriteria, true);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
locationManager.requestLocationUpdates(provider, 20000, 0, this);
}
Notification notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANEL_ID).setContentTitle("LocationTracker")
.setContentText("Фоновый режим запущен").setPriority(PRIORITY_DEFAULT)
.setCategory(NotificationCompat.CATEGORY_SERVICE).build();
startForeground(1411, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANEL_ID).setContentTitle("LocationTracker")
.setContentText("Фоновый режим запущен").setPriority(PRIORITY_DEFAULT)
.setCategory(NotificationCompat.CATEGORY_SERVICE).build();
startForeground(1411, notification);
if (locationManager == null) {
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria locationCriteria = new Criteria();
locationCriteria.setAccuracy(Criteria.NO_REQUIREMENT);
locationCriteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
String provider = locationManager.getBestProvider(locationCriteria, true);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
locationManager.requestLocationUpdates(provider, 20000, 0, this);
}
}
return Service.START_STICKY;
}
public void setListener(LocationUpdateListener updateListener) {
this.updateListener = updateListener;
}
@Override
public void onLocationChanged(@NonNull Location location) {
if (updateListener != null) {
locations += formatMillisToHours(System.currentTimeMillis()) + ": " + location.getLatitude() + ", " + location.getLongitude() + "\n";
updateListener.onLocationUpdated(locations);
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(@NonNull String provider) {
}
@Override
public void onProviderDisabled(@NonNull String provider) {
}
public void removeListener(LocationUpdateListener updateListener) {
if (this.updateListener != null) {
this.updateListener = null;
}
}
public class Binder extends android.os.Binder {
public LocationService getService() {
return LocationService.this;
}
}
public static String formatMillisToHours(long millis) {
@SuppressLint("SimpleDateFormat")
DateFormat formatter = new SimpleDateFormat("HH:mm:ss");
Date date = new Date(millis);
return formatter.format(date);
}
@Override
public void onDestroy() {
super.onDestroy();
locationManager.removeUpdates(this);
}
我的应用程序 class onCreate:
@Override
public void onCreate() {
super.onCreate();
NotificationChannel channel;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channel = new NotificationChannel(LocationService.NOTIFICATION_CHANEL_ID,
"LocationTrackerChannel", NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
}
几天前,我找到了答案,希望对某人有所帮助。 问题出在小我设备的 BatterySaver 服务中。 当我将其从默认的“省电模式”切换到“无限制”时,我的前台服务开始接收位置更新。 以下代码提供了一些机会来通知用户您的应用程序需要在不受 MIUI BatterySaver 限制的情况下运行:
public static void checkDevice(final Activity activity){
String manufacturer = android.os.Build.MANUFACTURER;
if ("xiaomi".equalsIgnoreCase(manufacturer)) {
boolean notifiedAboutBatterySave = PreferencesManager.getInstance().isNotifiedAboutBatterySaveMode();
if (!notifiedAboutBatterySave) {
AlertDialog.Builder adb = new AlertDialog.Builder(activity);
adb.setPositiveButton("Go to settings", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
Intent intent = new Intent();
ComponentName componentName = new ComponentName("com.miui.powerkeeper", "com.miui.powerkeeper.ui.HiddenAppsConfigActivity");
intent.setComponent(componentName);
intent.putExtra("package_name", activity.getPackageName());
intent.putExtra("package_label", activity.getText(R.string.app_name));
activity.startActivityForResult(intent, BATTERY_SAVE_MODE_REQUEST_CODE);
} catch (ActivityNotFoundException e) {
e.printStackTrace()
}
}
});
AlertDialog alert = adb.create();
alert.setTitle("Attention");
alert.setMessage("message about battery saver mode");
alert.setCancelable(true);
alert.show();
}
}
}
我没有找到任何可以帮助识别当前 BatterySaver 模式的解决方案来检查用户是否切换了此模式。 这就是为什么我只在用户第一次使用我的应用程序时向他显示此警报并祈祷)如果有人能找到更好的解决方案来处理这种情况,请在此处发布您的答案,我会将其标记为正确的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.