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

时间:2019-05-28 05:52:53

标签: java android

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

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
                {
                }
            }
    }
}

2 个答案:

答案 0 :(得分:2)

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

此onFor方法中新的ForegroundService的下一步调用startForeground()。使用startForeground,您必须传递一条通知以通知用户该服务正在运行。

此外,我发现某些设备(例如HUAWEI)具有称为“功耗密集型应用程序监视器”的功能。除非用户为其授予特殊权限,否则它将杀死长时间在后台运行的每个应用程序。执行此操作的路径:设置->安全和隐私->位置服务->最近的位置请求:您的应用名称->电池->取消选中耗电大的提示,应用启动:手动管理:检查所有三个位置:自动启动,二次启动,在后台运行。

我不知道有没有办法以编程方式执行此操作。我认为最好的方法是创建一种帮助活动,并向用户解释如果应用程序无法运行该怎么办。

答案 1 :(得分:0)

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

y

然后在“活动”中添加按钮或切换按钮以启动和停止服务。您也可以通过“通知”中的按钮进行操作。

rect

即使应用被终止,服务也应运行。在小米,OPPO,VIVO等设备中,无论您在服务中做什么,它都可能被杀死。在这些情况下,您可以尝试通过广播再次重新启动服务,以在服务被终止时启动该服务。

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); } 中。如果将活动从后台删除后的某个时间被杀死,则可以将其添加到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()

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