Java 当应用程序也从后台删除时,无法获取位置更新

Java 当应用程序也从后台删除时,无法获取位置更新,java,android,Java,Android,“我正试图在后台获取位置,但它显示了此错误。我无论如何都无法获取位置。通知不起作用。我的doMystuff()函数在主活动中应该是什么样子的?有人能提供我如何在清单中注册广播接收器,以及如何使用onButton Click实现代码吗?” 更新[2]:“我刚刚在这里写入了要访问的运行时权限。现在,单击doStuff函数中的“startButton”按钮,我应该写入startService还是startForegroundService?” “主要活动” 你应该使用ForegroundService

“我正试图在后台获取位置,但它显示了此错误。我无论如何都无法获取位置。通知不起作用。我的doMystuff()函数在主活动中应该是什么样子的?有人能提供我如何在清单中注册广播接收器,以及如何使用onButton Click实现代码吗?” 更新[2]:“我刚刚在这里写入了要访问的运行时权限。现在,单击doStuff函数中的“startButton”按钮,我应该写入startService还是startForegroundService?” “主要活动”


你应该使用ForegroundService而不是Service。要启动startForegroundService()时调用它

接下来,在onCreate方法中的新ForegroundsService中调用startForeground()。使用startForeground,您必须传递通知以通知用户服务正在运行

此外,我发现像华为这样的一些设备有一个叫做“电源密集型应用程序监视器”的功能“。它会杀死所有在后台长时间运行的应用程序,除非用户授予其特殊权限。执行此操作的路径:设置->安全和隐私->位置服务->最近的位置请求:您的应用程序名称->电池->取消选中耗电量大的提示,应用程序启动:手动管理:检查所有三个位置:自动启动,秒启动。”dary启动,在后台运行


我不知道有没有一种方法可以通过编程来实现这一点。我认为最好的方法是创建一种帮助活动,并向用户解释如果应用程序不起作用该怎么办。

您应该使用ForegroundsService而不是Service。要启动它,请调用StartForegroundsService()

接下来,在onCreate方法中调用startForeground()的新ForegroundService中。使用startForeground,您必须传递通知以通知用户服务正在运行

此外,我发现像华为这样的一些设备有一个叫做“电源密集型应用程序监视器”的功能“。它会杀死所有在后台长时间运行的应用程序,除非用户授予其特殊权限。执行此操作的路径:设置->安全和隐私->位置服务->最近的位置请求:您的应用程序名称->电池->取消选中耗电量大的提示,应用程序启动:手动管理:检查所有三个位置:自动启动,秒启动。”dary启动,在后台运行


我不知道有没有一种方法可以通过编程来实现这一点。我认为最好的方法是创建一种帮助活动,并向用户解释如果应用程序无法工作该怎么做。

每10秒更新一次位置的服务代码

public class LocationService extends Service implements com.google.android.gms.location.LocationListener,
        GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{

    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;

    private String mChannelId = "my_service";
    private int mNotificationId = 1;
    private NotificationCompat.Builder mNotifBuilder = new NotificationCompat.Builder(this, mChannelId);
    private Notification mNotif;
    private NotificationManager mNotificationManager;
    private boolean mRestartService = true;
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void initGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initGoogleApiClient();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null && intent.getAction() != null) {
            String mAction = intent.getAction();
            if(mAction.equals("start_service")){
                startForegroundService();
            }else if(mAction.equals("stop_service")){
                stopForegroundService();
            }
        }
        return START_NOT_STICKY;
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10000);
        mLocationRequest.setFastestInterval(5000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        try {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

    }

    @Override
    public void onLocationChanged(Location location) {
        Toast.makeText(this, "Location Updated", Toast.LENGTH_SHORT).show();
        //Broadcast Location
    }

    private void createNotificationChannel(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String description = "Foreground Service Channel";
            String name = "My Background Channel";
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel channel = new NotificationChannel(mChannelId, name, importance);
            channel.setDescription(description);
            mNotificationManager.createNotificationChannel(channel);
        }
    }

    private void startForegroundService() {
        //Initializing Notifications and intents
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);

        createNotificationChannel();

        mNotifBuilder.setContentText("Notification Content")
                .setContentTitle("Notification Title")
                .setSmallIcon(R.drawable.ic_notify)
                .setContentIntent(pendingIntent)
                .setOngoing(true)
                .setAutoCancel(true);

        mNotif = mNotifBuilder.build();
        startForeground(mNotificationId, mNotif);
    }

    private void stopForegroundService() {
        mRestartService = false;
        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
        stopForeground(true);
    }

    /*@Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Toast.makeText(this, "Task Removed", Toast.LENGTH_SHORT).show();
        if (mRestartService){
            Intent intent = new Intent(this, RestartService.class);
            intent.setAction("restart_service");
            sendBroadcast(intent);
        }
    }*/
}
然后在活动中添加按钮或切换按钮以启动和停止服务。您也可以使用通知中的按钮来执行此操作

private void startService() {
        Intent intent = new Intent(MainActivity.this, LocationService.class);
        intent.setAction("start_service");
        startService(intent);
    }

private void stopService() {
    Intent intent = new Intent(MainActivity.this, LocationService.class);
    intent.setAction("stop_service");
    startService(intent);
}
即使应用程序被终止,服务也应该运行。在一些设备中,如小米、OPPO、维梧……等,无论您在服务中做了什么,它都可能被终止。在这些设备中,您可以尝试通过广播重新启动服务,以便在服务终止时启动服务

public class RestartService extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if(action.equals("restart_service")){
            Intent intent1 = new Intent(context, LocationService.class);
            intent.setAction("start_service");
            context.startService(intent1);
        }
    }
}
如果从后台删除活动时服务被终止,则可以将其添加到
onTaskRemoved()
中。如果从后台删除活动后某个时间服务被终止,则可以将其添加到
ondestory()

public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Toast.makeText(this, "Task Removed", Toast.LENGTH_SHORT).show();
        if (mRestartService){
            Intent intent = new Intent(this, RestartService.class);
            intent.setAction("restart_service");
            sendBroadcast(intent);
        }
    }

即使这样,某些手机上的服务也可能会被终止。在这种情况下,您需要要求用户将该服务从电池优化中排除,并允许其他例外情况自由运行。

服务代码每10秒更新一次位置

public class LocationService extends Service implements com.google.android.gms.location.LocationListener,
        GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{

    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;

    private String mChannelId = "my_service";
    private int mNotificationId = 1;
    private NotificationCompat.Builder mNotifBuilder = new NotificationCompat.Builder(this, mChannelId);
    private Notification mNotif;
    private NotificationManager mNotificationManager;
    private boolean mRestartService = true;
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void initGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initGoogleApiClient();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null && intent.getAction() != null) {
            String mAction = intent.getAction();
            if(mAction.equals("start_service")){
                startForegroundService();
            }else if(mAction.equals("stop_service")){
                stopForegroundService();
            }
        }
        return START_NOT_STICKY;
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(10000);
        mLocationRequest.setFastestInterval(5000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        try {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

    }

    @Override
    public void onLocationChanged(Location location) {
        Toast.makeText(this, "Location Updated", Toast.LENGTH_SHORT).show();
        //Broadcast Location
    }

    private void createNotificationChannel(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String description = "Foreground Service Channel";
            String name = "My Background Channel";
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel channel = new NotificationChannel(mChannelId, name, importance);
            channel.setDescription(description);
            mNotificationManager.createNotificationChannel(channel);
        }
    }

    private void startForegroundService() {
        //Initializing Notifications and intents
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);

        createNotificationChannel();

        mNotifBuilder.setContentText("Notification Content")
                .setContentTitle("Notification Title")
                .setSmallIcon(R.drawable.ic_notify)
                .setContentIntent(pendingIntent)
                .setOngoing(true)
                .setAutoCancel(true);

        mNotif = mNotifBuilder.build();
        startForeground(mNotificationId, mNotif);
    }

    private void stopForegroundService() {
        mRestartService = false;
        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }
        stopForeground(true);
    }

    /*@Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Toast.makeText(this, "Task Removed", Toast.LENGTH_SHORT).show();
        if (mRestartService){
            Intent intent = new Intent(this, RestartService.class);
            intent.setAction("restart_service");
            sendBroadcast(intent);
        }
    }*/
}
然后在活动中添加按钮或切换按钮以启动和停止服务。您也可以使用通知中的按钮来执行此操作

private void startService() {
        Intent intent = new Intent(MainActivity.this, LocationService.class);
        intent.setAction("start_service");
        startService(intent);
    }

private void stopService() {
    Intent intent = new Intent(MainActivity.this, LocationService.class);
    intent.setAction("stop_service");
    startService(intent);
}
即使应用程序被终止,服务也应该运行。在一些设备中,如小米、OPPO、维梧……等,无论您在服务中做了什么,它都可能被终止。在这些设备中,您可以尝试通过广播重新启动服务,以便在服务终止时启动服务

public class RestartService extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if(action.equals("restart_service")){
            Intent intent1 = new Intent(context, LocationService.class);
            intent.setAction("start_service");
            context.startService(intent1);
        }
    }
}
如果从后台删除活动时服务被终止,则可以将其添加到
onTaskRemoved()
中。如果从后台删除活动后某个时间服务被终止,则可以将其添加到
ondestory()

public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Toast.makeText(this, "Task Removed", Toast.LENGTH_SHORT).show();
        if (mRestartService){
            Intent intent = new Intent(this, RestartService.class);
            intent.setAction("restart_service");
            sendBroadcast(intent);
        }
    }

即使这样,某些手机上的服务也可能会被终止。在这种情况下,您需要要求用户将该服务从电池优化中排除,并允许其他例外情况使其自由运行。

当应用程序从后台删除时,您能看到该服务的锁定通知吗?如果不能,则该服务可能会被终止活动终止时终止。您可以重写
OnDestroy()
MainActivity
LocationUpdateService
中,添加一些日志以检查发生了什么。是的,当从后台删除应用程序时,通知也会消失。然后当从后台删除应用程序时,服务会被终止。这可能是因为您正在绑定服务和活动。请尝试删除绑定/解除绑定机制,并独立运行服务。如果服务仍被终止,请尝试
返回START\u STICKY;'in your
onStartCommand',或在
onDestroy
onTaskRemoved
中再次重新启动服务。您可以查看答案以获得有关保持服务活动的更多帮助。@Arun先生,请检查我的新实现,并告诉我我做错了什么?我已经发布了一个带有工作代码的答案。你可以使用它。当应用程序从后台删除时,你是否能够看到服务的固定通知?如果不是,那么当活动被终止时,服务很可能被终止。你可以覆盖
OnDestroy()
MainActivity
LocationUpdateService
中,添加一些日志以检查发生了什么。是的,当从后台删除应用程序时,通知也会消失。然后,当从后台删除应用程序时,服务会被终止。这可能是因为您正在绑定服务