位置 api 有时在 android 中使用 google fused api 不给出确切的当前位置

Posted

技术标签:

【中文标题】位置 api 有时在 android 中使用 google fused api 不给出确切的当前位置【英文标题】:location api does not give exact current location sometime in android using google fused api 【发布时间】:2016-05-19 03:17:33 【问题描述】:

我使用以下代码在谷歌地图中获取当前位置和路径。我面临的问题是当前设备位置一直不稳定。它有时会显示正确的位置,但会显示不同的位置,例如距离实际位置 1 公里。

package com.colors.organisatiom.activity.colors;


import android.Manifest;
import android.annotation.TargetApi;
import android.app.AlertDialog;
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.graphics.Color;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.colors.organisatiom.activity.colors.classes.ConnectionManager;
import com.colors.organisatiom.activity.colors.interfaces.PolyLineCallback;
import com.colors.organisatiom.activity.colors.json.GetDistanceFromServer;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;

import java.util.ArrayList;
import java.util.List;

public class LocationMap extends AppCompatActivity implements LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener 
    private GoogleMap map;
    private String serviceCentreLongitude, serviceCentreLatitude, serviceCenhterLocation;
    final private int REQUEST_CODE_ASK_PERMISSIONS = 123;
    private RelativeLayout connectingParent;
    private PolylineOptions polylineOptions;
    private Polyline polyline;
    private List<Polyline> polylines = new ArrayList<>();
    private GoogleApiClient googleApiClient;
    private LocationRequest locationRequest;
    private static final long INTERVAL = 1 * 5;
    private static final long FASTEST_INTERVAL = 10;
    protected BroadcastReceiver mNotificationReceiver;
    private Marker currentLocationMarker;


    protected void createLocationRequest() 
        locationRequest = new LocationRequest();
        locationRequest.setInterval(INTERVAL);
        locationRequest.setFastestInterval(FASTEST_INTERVAL);
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        serviceCentreLatitude = getIntent().getStringExtra("latitude");
        serviceCentreLongitude = getIntent().getStringExtra("longitude");
        serviceCenhterLocation = getIntent().getStringExtra("service_center_location");
        setContentView(R.layout.content_google_map);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        Window window = this.getWindow();
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 
            window.setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
        
        mNotificationReceiver = new BroadcastReceiver() 
            @Override
            public void onReceive(Context context, Intent intent) 
                if (!LocationMap.this.isFinishing()) 
                    AlertDialog.Builder builder = new AlertDialog.Builder(LocationMap.this);
                    builder.setTitle(intent.getStringExtra("title"));
                    builder.setMessage(intent.getStringExtra("message"));
                    builder.setPositiveButton("Dismiss", new DialogInterface.OnClickListener() 
                        @Override
                        public void onClick(DialogInterface dialog, int which) 
                            //alertDialog.dismiss();
                        
                    );
                    final AlertDialog alertDialog = builder.create();
                    alertDialog.show();
                
            
        ;
        if (!isGooglePlayServicesAvailable()) 
            Toast.makeText(this, "Google play service not supported", Toast.LENGTH_LONG).show();
        
        createLocationRequest();
        googleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
        map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
                .getMap();
        connectingParent = (RelativeLayout) findViewById(R.id.connecting_parent);
        if (!new ConnectionManager(this).isConnectionToInternet()) 
            connectingParent.setVisibility(View.GONE);
            Toast.makeText(LocationMap.this, "No internet connection to route path", Toast.LENGTH_LONG).show();
        
        ImageView search = (ImageView) findViewById(R.id.search);
        search.setVisibility(View.INVISIBLE);
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
            int hasAccessCoarseLocationPermission = checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION);
            int hasAccessFineLocationPermission = checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION);
            if (hasAccessCoarseLocationPermission != PackageManager.PERMISSION_GRANTED && hasAccessFineLocationPermission != PackageManager.PERMISSION_GRANTED) 
                requestPermissions(new String[]Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION,
                        REQUEST_CODE_ASK_PERMISSIONS);
             else 
                showMapWithLocation();
                if (googleApiClient.isConnected()) 
                    startLocationUpdates();
                
            

         else 
            showMapWithLocation();
            if (googleApiClient.isConnected()) 
                startLocationUpdates();
            
        

    

    @Override
    public void onStart() 
        super.onStart();
        Log.d("Started:", "onStart fired ..............");
        googleApiClient.connect();
    

    @Override
    public void onStop() 
        super.onStop();
        Log.d("Stopped", "onStop fired ..............");
        googleApiClient.disconnect();
        Log.d("Is connected status", "isConnected ...............: " + googleApiClient.isConnected());
    

    private void showMapWithLocation() 
        map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        LatLng latLng = new LatLng(Double.parseDouble(serviceCentreLatitude), Double.parseDouble(serviceCentreLongitude));
        map.addMarker(new MarkerOptions()
                .position(latLng)
                .title(serviceCenhterLocation)).showInfoWindow();
        map.getUiSettings().setMapToolbarEnabled(false);
        CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 14);
        map.animateCamera(cameraUpdate);
    

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) 
        switch (requestCode) 
            case REQUEST_CODE_ASK_PERMISSIONS:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                    startLocationUpdates();
                    if (googleApiClient.isConnected()) 
                        startLocationUpdates();
                    
                 else 
                    Toast.makeText(LocationMap.this, "Cannot show map", Toast.LENGTH_SHORT)
                            .show();
                
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        
    

    private List<LatLng> decodePoly(String encoded) 
        List<LatLng> poly = new ArrayList<>();
        int index = 0, len = encoded.length();
        int lat = 0, lng = 0;
        while (index < len) 
            int b, shift = 0, result = 0;
            do 
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
             while (b >= 0x20);
            int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lat += dlat;
            shift = 0;
            result = 0;
            do 
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
             while (b >= 0x20);
            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lng += dlng;
            LatLng p = new LatLng((((double) lat / 1E5)),
                    (((double) lng / 1E5)));
            poly.add(p);
        
        return poly;
    


    @Override
    public void onConnected(Bundle bundle) 
        Log.e("Connection status:", "onConnected - isConnected ...............: " + googleApiClient.isConnected());
        startLocationUpdates();
    

    protected void startLocationUpdates() 
        LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
        Log.e("Update started:", "Location update started ..............: ");
    

    @Override
    public void onLocationChanged(Location location) 

            final double myLocationlatitude = location.getLatitude();
            final double myLocationlongitude = location.getLongitude();
            Log.e("Latitude", String.valueOf(myLocationlatitude));
            Log.e("Longitude", String.valueOf(myLocationlongitude));
            LatLng latLng = new LatLng(myLocationlatitude, myLocationlongitude);
            //drawing the path in google map
            //zoom the camera for the first time
            if (currentLocationMarker != null) 
                currentLocationMarker.remove();
            
            MarkerOptions markerOptions = new MarkerOptions();
            markerOptions.position(latLng);
            markerOptions.title("My current location");
            markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
            currentLocationMarker = map.addMarker(markerOptions);
            if (polylines == null) 
                CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 14);
                map.animateCamera(cameraUpdate);
            
            new AsyncTask<Void, Void, Void>() 
                @Override
                protected Void doInBackground(Void... params) 
                    new GetDistanceFromServer(String.valueOf(myLocationlatitude), String.valueOf(myLocationlongitude), serviceCentreLatitude, serviceCentreLongitude).drawPath(new PolyLineCallback() 
                        @Override
                        public void polyLinePointsHolder(String points) 
                            //remove the path and draw the path in google map while updating
                            if (polylines != null) 
                                for (Polyline line : polylines) 
                                    line.remove();
                                
                            
                            List<LatLng> list = decodePoly(points);
                            polylineOptions = new PolylineOptions()
                                    .addAll(list)
                                    .width(12)
                                    .color(Color.parseColor("#05b1fb"))
                                    .geodesic(true);
                            polyline = map.addPolyline(polylineOptions);
                            polylines.add(polyline);

                        
                    );
                    return null;
                

                @Override
                protected void onPostExecute(Void aVoid) 
                    connectingParent.setVisibility(View.GONE);

                    super.onPostExecute(aVoid);
                
            .execute();



    

    @Override
    public void onConnectionSuspended(int i) 

    

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) 
        Log.e("Connection Failed", connectionResult.getErrorMessage());
    

    @Override
    protected void onPause() 
        super.onPause();
        stopLocationUpdates();
    

    protected void stopLocationUpdates() 
        LocationServices.FusedLocationApi.removeLocationUpdates(
                googleApiClient, this);
        Log.d("TAG", "Location update stopped .......................");
    

    private boolean isGooglePlayServicesAvailable() 
        int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (ConnectionResult.SUCCESS == status) 
            return true;
         else 
            GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
            return false;
        
    

    @Override
    public void onResume() 
        super.onResume();
        LocalBroadcastManager.getInstance(this).registerReceiver(mNotificationReceiver, new IntentFilter("1000"));
        if (googleApiClient.isConnected()) 
            startLocationUpdates();
            Log.d("TAG", "Location update resumed .....................");
        
    

【问题讨论】:

【参考方案1】:

位置的准确性可能会受到许多因素的影响,包括 GPS 覆盖范围、设备质量和该地区周围的 wifi 可用性。您可以做的是检查您获得的位置的准确性并决定是否继续。为此,您可以使用 Location 对象的 hasAccuracy()getAccuracy() 方法。

这是来自文档中关于 getAccuracy 方法的引用

获取此位置的估计精度,以米为单位。

我们将准确度定义为 68% 置信度的半径。换句话说,如果 您以该位置的纬度和经度为中心画一个圆圈, 并且半径等于精度,则有 68% 真实位置在圆圈内的概率。

在统计术语中,假设位置误差是随机的 具有正态分布,所以 68% 的置信度圆表示 一个标准差。请注意,在实践中,位置错误不会 总是遵循这样一个简单的分布。

这个精度估计只关心水平精度, 并且不指示方位、速度或高度的准确性,如果 这些都包含在此位置中。

如果此位置没有准确度,则返回 0.0。全部 LocationManager 生成的位置包括精度。

在您的 onLocationChanged 方法中,您可以执行以下操作

@Override
public void onLocationChanged(Location location) 
     if(location.hasAccuracy() && location.getAccuracy() < 100F) 
        // the location has accuracy and has an accuracy span within 100m radius
        // do whatever you want with this location and stop location listener
        stopLocationUpdates();
     

     // if the above code did not get executed, the location listener will work 
     // until a location with acceptable accuracy is obtained

【讨论】:

以上是关于位置 api 有时在 android 中使用 google fused api 不给出确切的当前位置的主要内容,如果未能解决你的问题,请参考以下文章

android 可以用go 语言吗

为啥Android有时无法获取位置

如何在android应用程序中检测位置是不是有效?

Android 定位服务耗尽电池 - 融合定位 API

地理定位 API 在 android 中以本地语言显示地址

go中一次处理许多GET请求