当用户看不到活动时,前台服务 Android Q小米设备中没有位置更新

问题描述

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...