Android服务不更新位置

Posted

技术标签:

【中文标题】Android服务不更新位置【英文标题】:Android Service not updating location 【发布时间】:2017-01-24 02:06:34 【问题描述】:

我需要每 1 分钟和每 5 米位移更新一次融合位置(我知道这是不好的做法,但为了测试和在日志中显示),我通过按钮开始服务 按下按钮后立即按下我得到位置在 logcat 中,但只有一次。根据 Service classonLocationChanged 应该每 1 分钟调用一次,但即使我的 GPS 几乎每分钟打开一次,然后在一段时间后关闭但仍然没有位置,它也不会再调用一次在 Logcat 中更新。我需要服务类来保持更新位置而不影响 UI 或主线程

这里是 logcat,它只显示一次位置更新

09-16 03:13:37.125 10419-10419/com.example.com.pro_working1 D/===Location Service===: Service onConnected Calling
09-16 03:13:37.125 10419-10419/com.example.com.pro_working1 D/===Location Service===: Start Location Update is Calling
09-16 03:13:38.315 10419-10419/com.example.com.pro_working1 D/===Location Service===: Service OnLocationChanged Calling
09-16 03:13:38.315 10419-10419/com.example.com.pro_working1 D/===Location Service===: Here is Updated Locations: Latitude 28.5XXXXX Longitude 77.2XXXXX
09-16 03:13:38.315 10419-10419/com.example.com.pro_working1 D/===Location Service===: Sending Location Starting  Accuracy is: 37.5

这是我的服务类

public class Location_Service_background extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener 
    public static final String TAG = "===Location Service===";
    GoogleApiClient apiClient;
    Location mCurrentLocation;
    LocationRequest locationRequest;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
        GoogleApiSetup();
        RequestLocationUpdates();
        Log.d(TAG,"OnStartCommand Is Calling ");
        return START_STICKY;
    

    @Override
    public IBinder onBind(Intent intent) 
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    



    @Override
    public void onCreate() 
        super.onCreate();

    


    @Override
    public void onDestroy() 
        super.onDestroy();
        if (apiClient.isConnected())
            Log.d(TAG,"Service On Destroy Calling and apiClient is Connected");
            StopLocationUpdates();
            apiClient.disconnect();
        
    

    @Override
    public void onLowMemory() 
        super.onLowMemory();
    

    @Override
    public void onConnected(@Nullable Bundle bundle) 
        Log.d(TAG,"Service onConnected Calling");
        if (mCurrentLocation != null) 
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) 
                return;
            
             mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(apiClient);

        
        else 
            Log.d(TAG,"Start Location Update is Calling");
            StartLocationUpdate();
        
    

    @Override
    public void onConnectionSuspended(int i) 
        Log.d(TAG,"Service OnConnectionSuspended Calling");
        apiClient.connect();
    

    @Override
    public void onLocationChanged(Location location) 
        Log.d(TAG,"Service OnLocationChanged Calling");
        mCurrentLocation=location;
        Log.d(TAG,"Here is Updated Locations: Latitude "+mCurrentLocation.getLatitude()+"Longitude "+mCurrentLocation.getLongitude());
        String Latitude= String.valueOf(mCurrentLocation.getLatitude());
        String Longitude=String.valueOf(mCurrentLocation.getLongitude());
        String Accuracy=String.valueOf(mCurrentLocation.getAccuracy());
        Log.d(TAG,"Sending Location Starting"+" "+" Accuracy is: "+mCurrentLocation.getAccuracy());


    

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) 
        Log.d(TAG,"Connection Failed Called "+connectionResult);
    



    private synchronized  void GoogleApiSetup() 
        apiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
        apiClient.connect();
    

    private void RequestLocationUpdates() 
        locationRequest = new LocationRequest();
        //1 Min = 60 seconds AND 1000 milliseconds in 1 second
        locationRequest.setInterval(60 * 1000);//5 Min 300 x 1000=300000
        locationRequest.setFastestInterval(60 * 1000);//2 Min
        locationRequest.setSmallestDisplacement(5);
        locationRequest.setMaxWaitTime(60*1000);
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    

    private void StopLocationUpdates() 
        LocationServices.FusedLocationApi.removeLocationUpdates(apiClient, this);
    

    private void StartLocationUpdate() 
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) 

            return;
        
        if (apiClient.isConnected()) 
            LocationServices.FusedLocationApi.requestLocationUpdates(apiClient, locationRequest, this);
        
        else 
            Log.d(TAG,"GoogleApiClient is not connected yet.Please Try Again");
            apiClient.connect();
        
    



【问题讨论】:

不使用 setsmallestdisplacement 试试看会发生什么 它显示了在没有setsmallestdisplacement 的情况下对onLocationUpdate 的调用,但是我如何使用带有setsmallestdisplacement 的定期更新。感谢您的帮助 【参考方案1】:

希望这有助于拯救我在这个问题上所经历的挫败感。我正在使用 FusedLocationAPI 来请求位置更新和 GoogleApiClient。我也通过服务执行此操作。

由于 setSmallestDisplacement() 绝对优先于其他参数,因此您不会在定时间隔内获得任何位置更新。所以即使你有

locationRequestTimeInterval = LocationRequest.create()
    .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
    .setInterval(1)    
    .setFastestInterval(1)    
    .setMaxWaitTime(1)    
    .setSmallestDisplacement(5);

在满足 minimumDisplacement 参数之前永远不会触发。

解决方案是创建两个单独的 LocationRequests... 一个仅与距离有关,一个仅与时间有关,并使用您的单个 GoogleApiClient 创建 2 个 requestLocationUpdates 命令,一个使用 Time LocationRequest ,另一个使用 Distance LocationRequest。

所以你的 2 个 LocationRequest 看起来像这样:

locationRequestDistanceInterval = LocationRequest.create()
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
            .setFastestInterval(0) // This MUST be set, otherwise no updates
            .setSmallestDisplacement(LOCATION_REQUEST_MIN_DISTNACE);

locationRequestTimeInterval = LocationRequest.create()
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
            .setInterval(PROVIDER_GPS_UPDATE_TIME_INTERVAL)
            .setFastestInterval(PROVIDER_GPS_UPDATE_TIME_INTERVAL);
请注意,必须在距离请求上设置 setFastestInterval() 值,否则不会触发距离请求。它不必为 0,但必须设置此字段。

然后在您的 GoogleApiClients onConnected() 中,您可以添加两个 requestLocationUpdates() 调用。

LocationServices.FusedLocationApi.requestLocationUpdates(
    mLocationClient, 
    locationRequestDistanceInterval, 
    new LocationListener() 
        @Override
        public void onLocationChanged(Location location) 
            // Handle your Distance based updates
        
    
);

LocationServices.FusedLocationApi.requestLocationUpdates(
    mLocationClient, 
    locationRequestTimeInterval, 
    new LocationListener() 
        @Override
        public void onLocationChanged(Location location) 
            // Handle your Time based updates
        
    
);  

您可以使用相同或单独的 LocationListener 来处理每个请求的响应。 希望这会有所帮助。

【讨论】:

.setFastestInterval(0) // This MUST be set, otherwise no updates 谢谢你,smallestDisplacement 没有用,文档也没有提到。【参考方案2】:

假设您实际上在预期更新之间将设备移动了 5 米以上,我认为 LocationRequest 类可能存在问题,其中 setSmallestDisplacement() 方法无法正常工作...或者至少它没有按预期工作。 (我在other posts 上看到过这些问题)。

您始终可以通过删除 setSmallestDisplacement() 来自己检查距离,而是执行以下操作:

onLocationChanged() 
    double distance = // [ calculate distance between current lat/long and previous lat/long ]
    if (distance > 5 meters) 
        // do your normal onLocationChanged() code here
    

还有一种可能是,由于某种原因,FusedLocationProvider 无法访问您的 GPS,而是使用 wifi 或手机信号塔...在这种情况下,5m 的距离太小而无法指定。你的日志说精度是 37.5 米,所以这似乎不够准确,无法测量 5 米。那么...也许您没有在清单中设置 FINE 访问权限?

还可能是运行时权限未正确完成的问题吗?您可以暂时将您的目标 SDK 设置为 22 以进行检查。

【讨论】:

我在室内检查,这就是为什么精度这么高,我有很好的位置许可,这就是 GPS 开启的原因,粗略的位置无法访问 GPS。如果我将位置更新设置为 5 米这不应该每 1 分钟停止一次位置更新。它就像每 1 分钟或每 5 米更新一次位置。如果 5 米没有交叉,则必须每 1 分钟更新一次,但当我使用 setsmallestdisplacement 和你时它不会更新建议计算两点之间的距离这是不可能的 因为在实际条件下我必须将间隔设置为 10 分钟或 15 分钟,如果用户在这些时间段内移动几英里,那么我会丢失他在这些时间段之间旅行的位置,所以我需要在 x 米之后坚持使用 API 方法发送位置 不幸的是,我没有意识到这是您对 setdisplacement 方法工作原理的理解。根据我的理解,该方法的意思是:仅当用户自上次被触发以来已经行进了至少 X 米时才触发 onLocationChanged 方法。这并不意味着:每 5 米开火一次,因为这需要手机进行持续的位置监控/计算,而您试图通过创建一个间隔来避免这种情况以节省电池。 设置位置更新之间的最小位移(以米为单位) 此行来自 android 官方文档。设置用户/设备更新位置之间的最小位移,您还应该检查上次调用的 API位置管理器以获取更多信息 android 如何发送更新 阅读此行 第三是距离的最小变化 ?我不知道还能怎么解释。如果你让它按照你想要的方式工作,请在此处更新。【参考方案3】:

小小帮助谁知道可以用

    int jarak = 10;
    int interval = 5;


    LocationRequest request = new LocationRequest();
    request.setInterval(interval*1000); //update lokasi 10 detik
    request.setFastestInterval(interval*1000); //dapat update dari aplikasi lain yg lebih cepat 10 detik
    //request.setSmallestDisplacement(1); //diupdate jika berpindah 1 meter
    request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);


    FusedLocationProviderClient client = LocationServices.getFusedLocationProviderClient(this);
    int permission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
    if(permission == PackageManager.PERMISSION_GRANTED) 



        client.requestLocationUpdates(request, new LocationCallback() 

            @Override
            public void onLocationResult(LocationResult locationResult) 
                List<Location> locationList = locationResult.getLocations();
                if (locationList.size() > 0) 
                    Location locationCurrent = locationList.get(locationList.size() - 1);


                    double latitude = locationCurrent.getLatitude();
                    double longitude = locationCurrent.getLongitude();

                    double lastlatitude = Double.parseDouble(prefs.getString("lastlatitude","0"));
                    double lastlongitude = Double.parseDouble(prefs.getString("lastlongitude","0"));

                    Location startPoint=new Location("LokasiA");
                    startPoint.setLatitude(latitude);
                    startPoint.setLongitude(longitude);

                    Location endPoint = new Location("LokasiB");
                    endPoint.setLatitude(lastlatitude);
                    endPoint.setLongitude(lastlongitude);

                    double distance = startPoint.distanceTo(endPoint);

                    Log.d(tag, "location update last " + endPoint);
                    if(distance > jarak) 
                        Log.d(tag, "location update new" + startPoint);
                        Log.d(tag, "location dest " + distance);

                        SharedPreferences.Editor editor = prefs.edit();
                        editor.putString("lastlatitude", String.valueOf(latitude));
                        editor.putString("lastlongitude", String.valueOf(longitude));
                        editor.apply();



                        Log.i("getLatitude:",String.valueOf(locationCurrent.getLatitude()) );
                        Log.i("getLongitude:",String.valueOf(locationCurrent.getLongitude()) );


                    

                


            
        ,null);
    

【讨论】:

以上是关于Android服务不更新位置的主要内容,如果未能解决你的问题,请参考以下文章

如何从后台服务android更新谷歌地图v2位置

LocationListener 在 android 服务中的某个时间后不提供更新

Android - 如何在服务的后台获取位置更新

可以停止位置更新,Android服务

Android 服务未收到位置更新

在 android 服务的单独线程中运行位置更新