简体   繁体   English

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

[英]Not getting location updates when App is removed from background also

"I am trying to get the location in the background but it is showing this error. I am unable to get the location anyway. Notification not working. How should my doMystuff() function look like in the main activity? Can someone please provide how can I register the broadcast receiver in manifest and how to implement the code with onButton Click." “我正在尝试在后台获取位置,但显示此错误。无论如何我都无法获取该位置。通知不起作用。我的doMystuff()函数在主要活动中应如何显示?有人可以提供如何我可以在清单中注册广播接收器,以及如何使用onButton Click实现代码。” UPDATE[2]: "Here I have just written the run-time permission to be accessed. Now on button click "startButton" in the doStuff function should I write startService or startForegroundService?" UPDATE [2]:“在这里,我刚刚编写了要访问的运行时权限。现在,在按钮上单击doStuff函数中的“ startButton”,我应该编写startService还是startForegroundService? "MAIN ACTIVITY" “主要活动”

package com.example.locationrunandall;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private TextView textView;
    private Button butt1, butt2;
    public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textview);
        butt1 = findViewById(R.id.butt1);
        butt2 = findViewById(R.id.butt2);


    }



    public void startButton(View view) {
        fetchCode();
    }

    private void fetchCode() {
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {

            // Permission is not granted
            if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                    Manifest.permission.ACCESS_FINE_LOCATION)) {
                // Show an explanation to the user *asynchronously* -- don't block
                new AlertDialog.Builder(this)
                        .setTitle("Required Location")
                        .setMessage("You have to get this permission to access the feature.")
                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ActivityCompat.requestPermissions(MainActivity.this,
                                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                        MY_PERMISSIONS_REQUEST_LOCATION);
                            }
                        })
                        .setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        }).create().show();
            } else {
                // No explanation needed; request the permission
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        MY_PERMISSIONS_REQUEST_LOCATION);

            }
        } else {
            // Permission has already been granted
            doMyStuff();
        }
    }

    private void doMyStuff() {
        Toast.makeText(this, "Working", Toast.LENGTH_SHORT).show();
        Intent intent = new Intent(this,ForeService.class);
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
            startForegroundService(intent);
        }else{
            startService(intent);
        }
    }   
    public void stopButton(View view) {
        Intent intent = new Intent(this,ForeService.class);
        stopService(intent);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            if(requestCode==MY_PERMISSIONS_REQUEST_LOCATION){
                if(grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
                    Intent gpsOptionsIntent = new Intent(
                            android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivity(gpsOptionsIntent);
                }else
                {
                }
            }
    }
}

You should use ForegroundService instead of Service. 您应该使用ForegroundService而不是Service。 Call startForegroundService() when you want to start it. 要启动它,请调用startForegroundService()。

Next in this new ForegroundService in onCreate method call startForeground(). 接下来,在此新的ForegroundService中,通过onCreate方法调用startForeground()。 With startForeground you have to pass a notification to inform the user that service is running. 使用startForeground,您必须传递一个通知,以通知用户该服务正在运行。

Moreover I've found that some devices like HUAWEI have a feature called “power-intensive app monitor“. 此外,我发现某些设备(例如HUAWEI)具有称为“功耗密集型应用程序监控器”的功能。 It kills every app that runs in the background for a long time unless user gives special permissions to it. 除非用户为其授予特殊权限,否则它将杀死长时间在后台运行的每个应用程序。 The path to do this: Settings -> Security & privacy -> Location services -> recent location requests: YOUR APP NAME -> Battery -> uncheck Power-intensive prompt, App launch: Manage manually: check all three positions: Auto-launch, secondary launch, run in background. 执行此操作的路径:设置->安全和隐私->位置服务->最近的位置请求:您的应用名称->电池->取消选中耗电大的提示,应用启动:手动管理:检查所有三个位置:自动启动,二次启动,在后台运行。

I don't know is there a way to do this programmatically. 我不知道有没有办法以编程方式执行此操作。 I think the best way is to create a sort of help activity and explain the user what to do if application won't work. 我认为最好的方法是创建一种帮助活动,并向用户解释如果应用程序无法正常工作该怎么办。

Service code to get Location update every 10 seconds 服务代码每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);
        }
    }*/
}

Then in your Activity add a button or a toggle button to start and stop the service. 然后在“活动”中添加按钮或切换按钮以启动和停止服务。 You can also do it with a button in the Notification. 您也可以通过“通知”中的按钮进行操作。

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);
}

The service should run even the app is killed. 即使应用被杀死,该服务也应运行。 In some devices like xiaomi, OPPO, VIVO...etc it might get killed regardless of what you do in the service. 在小米,OPPO,VIVO等设备中,无论您在服务中做什么,它都可能被杀死。 In those you can try to restart the service again with a broadcast to start the service when it is killed. 在这些情况下,您可以尝试通过广播再次重新启动服务,以在服务被终止时启动该服务。

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);
        }
    }
}

You can add it in onTaskRemoved() if the service is killed when the activity is removed from the background. 如果从后台删除活动时服务被杀死,则可以在onTaskRemoved()添加它。 You can add it in onDestroy() if it is killed sometime after the activity is removed from the background 如果在从后台删除活动后某个时间将其杀死,则可以将其添加到onDestroy()

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);
        }
    }

Even with this the service might be killed in some mobiles. 即使这样,该服务也可能在某些手机中被杀死。 In those cases you need to ask the user to exclude the service from battery optimizations and also allow other exceptions for it to run freely. 在这些情况下,您需要要求用户从电池优化中排除该服务,并允许其他例外使其自由运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当应用程序移至后台时,在前台服务中获取位置更新不起作用 - getting location updates in foreground service isn't working when app is moved to background 如何在从后台删除应用程序时停止 JobService Scheduled? - How to stop JobService Scheduled to when app is removed from background? 获取位置更新-Android - Getting location updates - Android 如果从最近的应用程序中删除了应用程序,则不会调用接收方 - Receiver not getting invoked if removed app from recents 我希望我的应用程序在(线程或作为服务)中运行,即使 onDestroy() 被调用(用户从后台删除) - I want my app to be running in a (Thread or as a service) even when onDestroy() is called (user removed from background) 在后台接收GPS位置更新 - Receive GPS Location updates in background 无法在后台获取位置更新 - Can not get location updates in background 在服务中频繁获取位置更新 - Getting Location Updates frequently in Service 删除或更新程序包时未调用BroadcastReceiver - BroadcastReceiver not being called when package is removed or updates 应用程序从后台删除时,广播接收器无法正常工作? - Broadcast Receiver is not working when application is removed from background?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM