无法使用 Google 的融合位置 API 获取位置

Posted

技术标签:

【中文标题】无法使用 Google 的融合位置 API 获取位置【英文标题】:Unable to get location using Google's fused location API 【发布时间】:2016-09-01 12:07:34 【问题描述】:

我正在尝试使用 Google 的融合位置 API 获取我的位置。为此,我创建了两个类。一个是 MainActivity,第二个是 FusedLocationService,其中 MainActivity 是主类。但我将经度和纬度设为 0.0。所以请帮助我。

这是我的 MainActivity 代码:-

public class MainActivity extends AppCompatActivity 

TextView tvLocation;
FusedLocationService fusedLocationService;
double latitude;
double longitude;

String locationResult = "";
Location location;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    tvLocation = (TextView) findViewById(R.id.tvLocation);
    fusedLocationService = new FusedLocationService(this);
    location = fusedLocationService.getLocation();

    if (null != location) 
        latitude = location.getLatitude();
        longitude = location.getLongitude();
        locationResult = "Latitude: " + latitude + "\n" +
                "Longitude: " + longitude + "\n";
     else 
        Timber.e("-error-%s", "Location Not Available!");
        locationResult = "Location Not Available!";
    

    Log.e("Lati ", String.valueOf(latitude));
    Log.e("longi ", String.valueOf(longitude));
    tvLocation.setText(locationResult);
   
 

这是我的 FusedLocationService 类:-

public class FusedLocationService implements LocationListener, GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener 

private static final long INTERVAL = 1000 * 30; //30sec
private static final long FASTEST_INTERVAL = 1000 * 5; // 5sec

Activity mActivity;
public LocationRequest locationRequest;
public GoogleApiClient googleApiClient;
public Location location;
public FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;

public FusedLocationService(Activity activity) 

    Timber.plant(new Timber.DebugTree());
    locationRequest = LocationRequest.create();
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationRequest.setInterval(INTERVAL);
    locationRequest.setFastestInterval(FASTEST_INTERVAL);
    mActivity = activity;
    googleApiClient = new GoogleApiClient.Builder(mActivity)
            .addApi(LocationServices.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

    if (googleApiClient != null) 
        googleApiClient.connect();
    



@Override
public void onConnected(Bundle connectionHint) 
    Log.e("-onConnected-", "connected now");
    location = fusedLocationProviderApi.getLastLocation(googleApiClient);
    fusedLocationProviderApi.requestLocationUpdates(googleApiClient, locationRequest, this);


@Override
public void onLocationChanged(Location location) 


public Location getLocation() 
    return location;


@Override
public void onConnectionSuspended(int i) 


@Override
public void onConnectionFailed(ConnectionResult connectionResult) 
  

我已在 gradle 文件夹中的清单和 lib 中包含权限。 所以请帮忙。提前谢谢你

【问题讨论】:

onConnected 方法中检查此代码googleApiClient.isConnected()。如果它返回false,那么应该有一个禁用位置的情况,可能是在电话或谷歌服务的设置中。 【参考方案1】:

缺少对新位置的引用:

@Override
public void onLocationChanged(Location location) 
    this.location = location;

位置更新也是异步。因此,您需要类似活动的回调

编辑:

还要检查 Google Play 服务是否可用。你可以像这样创建一个方法:

public boolean checkPlayServices() 
   return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS;

见Google documentation

【讨论】:

感谢您的回答,但在添加 this.location = location 到 onLocationChanged @momo 后仍然是同样的问题 不要在ActivityonCreate() 中调用location = fusedLocationService.getLocation();。这不起作用,因为该位置不是立即可用的。事实上,不要做任何需要onCreate() 中的位置的事情。当人们解释时,您只有在 onLocationChanged(Location location) 被调用后才有位置。重新设计您的代码,以便处理位置的任何内容仅在调用 onLocationChanged() 后运行。【参考方案2】:

简短说明

您正在获取全局纬度和经度变量的默认值

double latitude;
double longitude;

详细解释

当你实例化 FusedLocationService 类时

fusedLocationService = new FusedLocationService(this);

它构建 google api 客户端然后尝试连接

public FusedLocationService(Activity activity) 
    ...
    googleApiClient = new GoogleApiClient.Builder(mActivity)
        .addApi(LocationServices.API)
        .addConnectionCallbacks(this)
        .addOnConnectionFailedListener(this)
        .build();

    if (googleApiClient != null) 
        googleApiClient.connect();
    

连接成功后,发出定位请求

@Override
public void onConnected(Bundle connectionHint) 
    Log.e("-onConnected-", "connected now");
    location = fusedLocationProviderApi.getLastLocation(googleApiClient);
    fusedLocationProviderApi.requestLocationUpdates(googleApiClient, locationRequest, this);

连接google api,接收位置是异步操作。

这意味着,你必须倾向于他们的回调

但是在初始化 FusedLocationService 类之后,您正在使用纬度经度变量。所以这就是为什么你得到 0.0 作为纬度和经度。

Log.e("Lati ", String.valueOf(latitude));
Log.e("longi ", String.valueOf(longitude));
tvLocation.setText(locationResult);

编辑——收尾工作

首先,您可以删除或移动这些代码。您正在处理异步操作。

Log.e("Lati ", String.valueOf(latitude));
Log.e("longi ", String.valueOf(longitude));
tvLocation.setText(locationResult);

当 google api 连接时,检查之前收到的位置并更新你的用户界面(如果有)

@Override
public void onConnected(Bundle connectionHint) 
    ...
    Location location = fusedLocationProviderApi.getLastLocation(googleApiClient);
    // Provider could return null, because it tries to get location if any 
    if(location != null)
        // UPDATE YOUR UI
    
    fusedLocationProviderApi.requestLocationUpdates(googleApiClient, locationRequest, this);

收到新位置后,更新您的用户界面

@Override
public void onLocationChanged(Location location) 
    // You have received fresh location
    // UPDATE YOUR UI

还可以查看link,您会更好地理解我提到的各个方面。

【讨论】:

感谢您的解释。那么你能给我提供解决这个问题的方法吗?【参考方案3】:

我创建了一个名为 LocationActivity 的类

public class LocationActivitity extends AppCompatActivity
            implements LocationListener,
            GoogleApiClient.ConnectionCallbacks,
            GoogleApiClient.OnConnectionFailedListener 

        final String TAG = "GPS";
        private long UPDATE_INTERVAL = 2 * 1000;  /* 10 secs */
        private long FASTEST_INTERVAL = 2000; /* 2 sec */
        static final int MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;

        GoogleApiClient gac;
        LocationRequest locationRequest;
        public String tvLatitude, tvLongitude, tvTime;

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

            isGooglePlayServicesAvailable();

            if(!isLocationEnabled())
                showAlert();

            locationRequest = new LocationRequest();
            locationRequest.setInterval(UPDATE_INTERVAL);
            locationRequest.setFastestInterval(FASTEST_INTERVAL);
            locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            gac = new GoogleApiClient.Builder(this)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .addApi(LocationServices.API)
                    .build();
        

        @Override
        protected void onStart() 
            gac.connect();
            super.onStart();
        

        @Override
        protected void onStop() 
            gac.disconnect();
            super.onStop();
        

        @Override
        public void onLocationChanged(Location location) 
            if (location != null) 
                updateUI(location);
            
        

        @Override
        public void onConnected(@Nullable Bundle bundle) 
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED
                    && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED) 
                ActivityCompat.requestPermissions(this,
                        new String[]Manifest.permission.ACCESS_FINE_LOCATION,
                        MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);

                return;
            
            Log.d(TAG, "onConnected");

            Location ll = LocationServices.FusedLocationApi.getLastLocation(gac);
            Log.d(TAG, "LastLocation: " + (ll == null ? "NO LastLocation" : ll.toString()));

            LocationServices.FusedLocationApi.requestLocationUpdates(gac, locationRequest, this);
        

        @Override
        public void onRequestPermissionsResult(
                int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 

            switch (requestCode) 
                case MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: 
                    // If request is cancelled, the result arrays are empty.
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                        Toast.makeText(this, "Permission was granted!", Toast.LENGTH_LONG).show();

                        try
                            LocationServices.FusedLocationApi.requestLocationUpdates(
                                    gac, locationRequest, this);
                         catch (SecurityException e) 
                            Toast.makeText(this, "SecurityException:\n" + e.toString(), Toast.LENGTH_LONG).show();
                        
                     else 
                        Toast.makeText(this, "Permission denied!", Toast.LENGTH_LONG).show();
                    
                    return;
                
            
        

        @Override
        public void onConnectionSuspended(int i) 

        @Override
        public void onConnectionFailed(@NonNull ConnectionResult connectionResult) 
            Toast.makeText(this, "onConnectionFailed: \n" + connectionResult.toString(),
                    Toast.LENGTH_LONG).show();
            Log.d("DDD", connectionResult.toString());
        

        private void updateUI(Location loc) 
            Log.d(TAG, "updateUI");
            tvLatitude=loc.getLatitude()+"";
            tvLongitude=loc.getLongitude()+"";
            //tvTime.setText(DateFormat.getTimeInstance().format(loc.getTime()));
        

        private boolean isLocationEnabled() 
            LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
            return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
                    locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        

        private boolean isGooglePlayServicesAvailable() 
            final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
            GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
            int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
            if (resultCode != ConnectionResult.SUCCESS) 
                if (apiAvailability.isUserResolvableError(resultCode)) 
                    apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
                            .show();
                 else 
                    Log.d(TAG, "This device is not supported.");
                    finish();
                
                return false;
            
            Log.d(TAG, "This device is supported.");
            return true;
        

        private void showAlert() 
            final AlertDialog.Builder dialog = new AlertDialog.Builder(this);
            dialog.setTitle("Enable Location")
                    .setMessage("Your Locations Settings is set to 'Off'.\nPlease Enable Location to " +
                            "use this app")
                    .setPositiveButton("Location Settings", new DialogInterface.OnClickListener() 
                        @Override
                        public void onClick(DialogInterface paramDialogInterface, int paramInt) 

                            Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                            startActivity(myIntent);
                            finish();
                        
                    )
                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() 
                        @Override
                        public void onClick(DialogInterface paramDialogInterface, int paramInt) 
                        
                    );
            dialog.show();
        
    

这是获取位置的方法 updateUI(Location loc)。

【讨论】:

以上是关于无法使用 Google 的融合位置 API 获取位置的主要内容,如果未能解决你的问题,请参考以下文章

无法使用融合位置API停止位置更新

使用 Google Play 服务我可以在离线模式下获取最新位置吗(FusedLocationProvider Api)

Google Maps API v3和fusion图层:获取行数据

当应用程序和设备中的 Google Play 服务不同时,使用融合位置获取 CurrentLocation 0

如何从融合位置 api 中获取卫星数量?

融合位置 API 运行时权限错误