适用于Android 9及以上版本的FusedLocationProviderClient后台服务

3
我正在尝试使用FusedLocationProviderClient每隔10秒获取位置,但是当我最小化或终止应用程序时,位置更新会停止。以下是我的代码。目前我正在使用Android 9.0。我不知道为什么会发生这种情况,希望能提供任何帮助。
Android清单
        <service android:enabled="true" android:name=".LocationService">
        </service>

LocationService.java

package com.example.locationupdate;

import android.Manifest;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;

import com.example.locationupdate.db.Realm$Helper;
import com.example.locationupdate.shared_pref.SaveInSharedPreference;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.SettingsClient;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;

import java.util.List;

import static com.google.android.gms.location.LocationServices.getFusedLocationProviderClient;

public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener  {

    //private LocationRequest mLocationRequest;
    private long UPDATE_INTERVAL = 10 * 1000;  /* 10 secs */
    private long FASTEST_INTERVAL = 2000;
    int count = 0;

    List<FilterData> datafromDB;
    FusedLocationProviderClient mFusedLocationClient;
    LocationRequest mLocationRequest;


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    LocationCallback mLocationCallback = new LocationCallback(){
        @Override
        public void onLocationResult(LocationResult locationResult) {


            for (Location location : locationResult.getLocations()) {
                //Log.e("MainActivity", "Location: " + location.getLatitude() + " " + location.getLongitude());

                if (SaveInSharedPreference.getInSharedPreference(LocationService.this).getLat() == 0.0 && SaveInSharedPreference.getInSharedPreference(LocationService.this).getLng() == 0.0) {
                    SaveInSharedPreference.getInSharedPreference(LocationService.this).setLatLong(location.getLatitude(), location.getLongitude());
                }
                SaveInSharedPreference.getInSharedPreference(LocationService.this).setCurrentLatLong(location.getLatitude(), location.getLongitude());

                count = count + 1;

                Log.e("mLocationCallbackLat", String.valueOf(location.getLatitude()));
                Log.e("mLocationCallbackLong", String.valueOf(location.getLongitude()));
                //LocationMatch(location);
            }

           /* datafromDB = Realm$Helper.getLocation$Module(LocationService.this).getAllData();

            for (FilterData str : datafromDB) {

                String name = str.getName();

            }*/
        };

    };

    public void onResume() {
        Log.e("OnResume", "OnResumeEvent");
        if (mFusedLocationClient != null) {
            requestLocationUpdates();
        }
    }

    public void requestLocationUpdates() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(UPDATE_INTERVAL); // two minute interval
        mLocationRequest.setFastestInterval(FASTEST_INTERVAL);

        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
        }
    }


    public void onPause() {
        //super.onPause();
        Log.e("ONPause", "OnPauseEvent");
        if (mFusedLocationClient != null) {
            mFusedLocationClient.removeLocationUpdates(mLocationCallback);
        }
    }

    protected void startLocationUpdates() {

        // Create the location request to start receiving updates
        mLocationRequest = new LocationRequest();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setInterval(UPDATE_INTERVAL);
        mLocationRequest.setFastestInterval(FASTEST_INTERVAL);

        // Create LocationSettingsRequest object using location request
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
        builder.addLocationRequest(mLocationRequest);
        LocationSettingsRequest locationSettingsRequest = builder.build();

        // Check whether location settings are satisfied
        // https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient
        SettingsClient settingsClient = LocationServices.getSettingsClient(this);
        settingsClient.checkLocationSettings(locationSettingsRequest);

        // new Google API SDK v11 uses getFusedLocationProviderClient(this)
        getFusedLocationProviderClient(this).requestLocationUpdates(mLocationRequest, new LocationCallback() {
                    @Override
                    public void onLocationResult(LocationResult locationResult) {
                        // do work here
                        onLocationChanged(locationResult.getLastLocation());
                    }
                },
                Looper.myLooper());
    }

    public void onLocationChanged(Location location) {

        if (SaveInSharedPreference.getInSharedPreference(LocationService.this).getLat() == 0.0 && SaveInSharedPreference.getInSharedPreference(LocationService.this).getLng() == 0.0) {
            SaveInSharedPreference.getInSharedPreference(LocationService.this).setLatLong(location.getLatitude(), location.getLongitude());
        }
        SaveInSharedPreference.getInSharedPreference(LocationService.this).setCurrentLatLong(location.getLatitude(), location.getLongitude());

        Toast.makeText(this,"onLocationChanged",Toast.LENGTH_LONG);
        // New location has now been determined
        String msg = "Updated Location: " +
                Double.toString(location.getLatitude()) + "," +
                Double.toString(location.getLongitude());

        Log.e ("onLocationChangedLat", String.valueOf(location.getLatitude()));
        Log.e ("onLocationChangedLong", String.valueOf(location.getLongitude()));
        // You can now create a LatLng Object for use with maps
        LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());


            /*loc1.setLatitude(location.getLatitude());
            loc1.setLongitude(location.getLongitude());

            loc2.setLatitude(str.getLat());
            loc2.setLongitude(str.getlng());

            double distanceInMeters = loc1.distanceTo(loc2);
            Log.e("Name", name);
            Log.e("Distance", "" + distanceInMeters);*/
    }

    public void getLastLocation() {
        // Get last known recent location using new Google Play Services SDK (v11+)
        FusedLocationProviderClient locationClient = getFusedLocationProviderClient(this);

        locationClient.getLastLocation()
                .addOnSuccessListener(new OnSuccessListener<Location>() {
                    @Override
                    public void onSuccess(Location location) {
                        // GPS location can be null if GPS is switched off
                        if (location != null) {
                            onLocationChanged(location);
                        }
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.d("MapDemoActivity", "Error trying to get last GPS location");
                        e.printStackTrace();
                    }
                });
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {

    }

    @Override
    public void onConnectionSuspended(int i) {

    }

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

    }
}

MainActitvity.java

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //locationTv = findViewById(R.id.location);

        Intent startIntent = new Intent(this, LocationService.class);
        startService(startIntent);

1个回答

4

你可以通过设置处理程序并为android应用添加所需权限来实现此目的。显然根据Android后台位置,有一个限制,即你可以请求多少次后台位置,但我没有看到这一点。我每秒请求一次新的位置。

首先将以下内容添加到你的清单文件中:

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

然后您可以创建这样的处理程序。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    createLocationHandler();
    ...
}

createLocationHandler和isServiceRunning函数:

public void createLocationHandler(){
    HandlerThread locationHandler = new HandlerThread("LocationHandler"); //Creates a new handler thread
    locationHandler.start(); //Starts the thread
    Handler handler = new Handler(locationHandler.getLooper()); //Get the looper from the handler thread
    handler.postDelayed(new Runnable() {//Run the runnable only after the given time
        @Override
        public void run() {
            //Check if the location service is running, if its not. lets start it!
            if(!isMyServiceRunning(LocationService.class)){
                getApplicationContext().startService(new Intent(getApplicationContext(), LocationService.class));
            }
            //Requests a new location from the location service(Feel like it could be done in a less static way)
            LocationService.requestNewLocation();
            createLocationHandler();//Call the create location handler again, this will not be added to the stack because of the looper.
        }
    }, 10000);//Set the delay to be 10 seconds, 1 second = 1000 milliseconds
}

private boolean isMyServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) this.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

在启动服务之前,请记得要请求 background_location 权限。


1
感谢您的帮助。问题出在我的权限上,我按照下面链接中的指南进行了操作。我不知道Android 10引入了3个权限选项。https://www.journaldev.com/28028/android-10-location-permissions - Mohammad Saad Abdul Rahim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接