问题描述
我正在制作原型应用程序,它的唯一功能是从前台服务接收位置更新。我想我已经阅读了 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 类代码:
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,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);
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,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);
}
我的应用程序类 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 当前模式的解决方案,无论以任何方式检查用户是否切换了此模式。这就是为什么我只在用户第一次使用我的应用程序时向他显示此警报并祈祷) 如果有人能找到更好的解决方案来处理这种情况,请在此处发布您的答案,我会将其标记为正确的。