融合位置提供商似乎没有使用GPS接收器

时间:2014-01-09 13:59:47

标签: android geolocation gps google-play-services

Moto G上的Android 4.3,Nexus 7上的Android 4.4.2,Nexus 5上的Android 4.4.2.Android Studio 0.4。

我不想接收定期的位置更新,我只想在用户按下按钮时获得准确的位置。

我遵循了这个例子:https://developer.android.com/training/location/retrieve-current.html

在清单文件中:

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

我使用GooglePlayServicesUtil.isGooglePlayServicesAvailable检查Play服务是否可用

在主要活动中:

//in activity onCreate method
mLocationClient = new LocationClient(this, this, this);

@Override
protected void onStart() {
    mLocationClient.connect();
    super.onStart();
}

@Override
protected void onStop() {
    mLocationClient.disconnect();
    super.onStop();
}

//in button onclick method    
mCurrentLocation = mLocationClient.getLastLocation();

我没有SIM卡。如果我启用Wifi,有时我会得到一个准确的位置。其他时候mCurrentLocation为null。

如果我禁用Wifi,则mCurrentLocation始终为空。

我正在几个地方进行测试,总能清楚地看到天空。我在每个地方等了三分钟。

我从未在屏幕顶部的Android通知栏上看到GPS图标。

我有这些位置设置: enter image description here

GPS测试应用程序设法在禁用Wi-Fi的同一设备上在室内成功使用GPS,因此GPS正在工作: enter image description here

注册位置更新(例如https://developer.android.com/training/location/receive-location-updates.html)也不起作用。注册方法从未调用。

我做错了什么?

12 个答案:

答案 0 :(得分:16)

我解决了。问题是“让Google应用访问您的位置”已关闭: enter image description here

当我打开它时,我会获得GPS读数,当它关闭时我不会。

由于两个原因,我把它关了:

  1. 我正在开发一个应用程序,用于公司的许多设备,我希望最少的手动配置是必要的

  2. 屏幕上显示“此设置仅影响Google应用”。我知道Play服务是谷歌软件,但我认为谷歌不希望最终用户理解这一点。

  3. 然后我获得了Android 4.4.2更新,位置设置页面也发生了变化。看来我可以关闭谷歌位置报告,并仍然从融合的位置提供商获得GPS读数: enter image description here

    所以也许谷歌意识到这个设置令人困惑并改进了它。无论哪种方式,如果我几天前得到4.4.2,我会节省很多时间。

答案 1 :(得分:15)

问题在于getLastLocation(),因为它使用了缓存位置。我遇到了同样的问题,我也尝试使用这种简单的方法。因为,我已经切换到收听更新(并在第一次成功更新后自动停止)。

这是我的代码。

首先,检查应用程序中的可用性(不是必需的,可以在Activity中而不保留结果):

public class MainApp extends Application {
  public static enum PlayServices {
    NOT_CHECKED, AVAILABLE, UNAVAILABLE
  };
  public static PlayServices mPlayServices = PlayServices.NOT_CHECKED;

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

    if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
      MainApp.mPlayServices = MainApp.PlayServices.AVAILABLE;
    }
  }
}

然后,进入活动:

public class MainActivity extends SherlockFragmentActivity implements
  GooglePlayServicesClient.ConnectionCallbacks,
  GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {

在其onCreate()

if (MainApp.mPlayServices != MainApp.PlayServices.UNAVAILABLE) {
  mLocationClient = new LocationClient(this, this, this);

  mLocationRequest = LocationRequest.create();
  mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
  mLocationRequest.setInterval(5000);
  mLocationRequest.setNumUpdates(1);
  mLocationRequest.setFastestInterval(1000);

  mUpdatesRequested = false;
  MainApp.prefs.edit().putBoolean(MainApp.KEY_LOCATION_UPDATES_REQUESTED, mUpdatesRequested)
      .commit();
}

MainActivity类的其余部分:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  Log.d(this.getClass().getSimpleName(), "onActivityResult(" + requestCode + ", " + resultCode
      + ")");
  // Decide what to do based on the original request code
  switch (requestCode) {
    case MainApp.PLAY_CONNECTION_FAILURE_RESOLUTION_REQUEST:
      /*
       * If the result code is Activity.RESULT_OK, try
       * to connect again
       */
      switch (resultCode) {
        case Activity.RESULT_OK:
          // here we want to initiate location requests!
          mLocationClient = new LocationClient(this, this, this);

          break;
      }
      break;
  }
}

@Override
public void onConnected(Bundle dataBundle) {
  Log.d(this.getClass().getSimpleName(), "onConnected()");

  Log.d(this.getClass().getSimpleName(), "Google Play Services are available.");
  MainApp.mPlayServices = MainApp.PlayServices.AVAILABLE;

  if (!mUpdatesRequested) {

    LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    boolean gps_enabled = false;
    try {
      gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
    } catch (Exception ex) {
    }

    boolean network_enabled = false;
    try {
      network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    } catch (Exception ex) {
    }

    // don't start listeners if no provider is enabled
    MainApp.locEnabled = gps_enabled || network_enabled;

    if (!MainApp.locEnabled) {
      // we have access to PlayServices, but user has disabled location visibility --> alert him
      alertLocationOff();
    } else {
      mLocationClient.requestLocationUpdates(mLocationRequest, this);
      mUpdatesRequested = true;
    }
  }
}

@Override
public void onDisconnected() {
  Log.d(this.getClass().getSimpleName(), "onDisconnected()");
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
  Log.d(this.getClass().getSimpleName(), "onConnectionFailed()");

  Log.d(this.getClass().getSimpleName(), "Google Play Services not available.");
  MainApp.mPlayServices = MainApp.PlayServices.UNAVAILABLE;

  /*
   * Google Play services can resolve some errors it detects.
   * If the error has a resolution, try sending an Intent to
   * start a Google Play services activity that can resolve
   * error.
   */
  if (connectionResult.hasResolution()) {
    try {
      // Start an Activity that tries to resolve the error
      connectionResult.startResolutionForResult(this,
          MainApp.PLAY_CONNECTION_FAILURE_RESOLUTION_REQUEST);
      /*
       * Thrown if Google Play services canceled the original
       * PendingIntent
       */
    } catch (IntentSender.SendIntentException e) {
      // Log the error
      e.printStackTrace();
    }
  } else {
    /*
     * If no resolution is available, display a dialog to the
     * user with the error.
     */
    GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), this, 0).show();
  }
}

@SuppressLint("NewApi")
@Override
public void onLocationChanged(Location location) {
  Log.d(this.getClass().getSimpleName(), "onLocationChanged(), location=" + location);

  if (location != null) {
    boolean present = true;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
      present = Geocoder.isPresent();
    }

    if (present) {
      (new ExtractLocationTask(this)).execute(location);
    } else {
      Log.e(this.getClass().getSimpleName(), "Geocoder not present");
      MainApp.mPlayServices = MainApp.PlayServices.UNAVAILABLE;
    }
  }
}


private class ExtractLocationTask extends AsyncTask<Location, Void, Boolean> {
  Context mContext;

  public ExtractLocationTask(Context context) {
    super();
    mContext = context;
  }

  @Override
  protected Boolean doInBackground(Location... params) {
    Log.d(getClass().getSimpleName(), "ExtractLocationTask.onPreExecute()");

    boolean found = false;
    try {
      Geocoder geoCoder_local = new Geocoder(mContext, Locale.getDefault());
      Geocoder geoCoder_en = new Geocoder(mContext, Locale.ENGLISH);

      List<Address> addresses_local = geoCoder_local.getFromLocation(params[0].getLatitude(),
          params[0].getLongitude(), 10);
      List<Address> addresses_en = geoCoder_en.getFromLocation(params[0].getLatitude(),
          params[0].getLongitude(), 10);

      if (addresses_local != null && addresses_local.size() > 0) {

        // do what you want with location info here

        // based on mLocationRequest.setNumUpdates(1), no need to call
        // removeLocationUpdates()

        MainApp.locEnabled = true;

        mUpdatesRequested = false;
        MainApp.prefs.edit()
            .putBoolean(MainApp.KEY_LOCATION_UPDATES_REQUESTED, mUpdatesRequested).commit();

        found = true;
      }
    } catch (IOException e) {
      Log.e(this.getClass().getSimpleName(), "Exception: ", e);
    }

    return found;
  }

  @Override
  protected void onPostExecute(Boolean found) {
    Log.d(getClass().getSimpleName(), "ExtractLocationTask.onPostExecute()");

    if (found) {
      // update UI etc.
    } else if (!mUpdatesReRequested) {
      mLocationClient.requestLocationUpdates(mLocationRequest, (LocationListener) mContext);
      mUpdatesRequested = true;
      mUpdatesReRequested = true;
    }
  }
}

我希望这会帮助你让它发挥作用!

答案 2 :(得分:4)

在某些客户要求(订阅)高精度位置之前,位置提供商不会唤醒GPS(如其他用户给出的示例中所述)。 GPS测试应用程序不使用位置提供程序,而是使用旧的“直接”方式获取位置。

此外还有到期机制,如果认为它是陈旧的,会在一段时间后删除有关上一个位置的信息。

总结以上所有内容,LP(位置提供商)确实无法为您提供任何帮助。

答案 3 :(得分:2)

我认为您正在室内测试您的应用程序,它不起作用..

和代码流..

public void setUpLocationClientIfNeeded() {
        createLocReq();
        if (mLocationClient == null) {
            mLocationClient = new LocationClient(getApplicationContext(), this, // ConnectionCallbacks
                    this); // OnConnectionFailedListener
        }
    }

    private void createLocReq() {
        if (mLocationRequest == null) {
            // Create a new global location parameters object
            mLocationRequest = LocationRequest.create();
            // Set the update interval
            mLocationRequest.setInterval(LocationServices.UPDATE_INTERVAL_IN_MILLISECONDS);
            // Use high accuracy
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            // Set the interval ceiling to one minute
            mLocationRequest.setFastestInterval(LocationServices.FAST_INTERVAL_CEILING_IN_MILLISECONDS);

            mLocationClient = new LocationClient(getApplicationContext(), this, this);
            mLocationClient.connect();
        }
    }

    public void updateLocation(Location location) {
        if (lastTrackedLat == 0.0) {
            lastTrackedLat = location.getLatitude();
        }
        if (lastTrackedLng == 0.0) {
            lastTrackedLng = location.getLongitude();
        }

        currentLat = location.getLatitude();
        currentLng = location.getLongitude();
    }

    @Override
    public void onLocationChanged(Location location) {
        if (location != null) {
            this.location = location;
            updateLocation(location);
        }
    }

    public Location getLocation() {
        // mLocationClient.getLastLocation();
        return location;
    }

答案 4 :(得分:1)

根据文档

此方法提供了获取位置的简化方法。 它特别适用于不需要准确位置的应用程序,并且不希望为位置更新维护额外的逻辑。

所以它可能会也可能不会返回高度准确的位置。

GPS可能需要一段时间才能锁定,因此调用getLastLocation可能会也可能不会返回位置

您最好请求位置更新,然后在获得位置后停止请求位置更新。

同时查看您提供的代码是否在等待LocationClient连接之前尝试获取位置?这肯定会给你一个空位置,因为它还没有连接到位置。

你应该做的是在onConnected获取最后一个位置,例如

public void onConnected(Bundle connectionHint) {
    Location location = mLocationClient.getLastLocation();
}

正如在该示例中所说的onConnected是Called by Location Services when the request to connect the client finishes successfully. At this point, you can request the current location or start periodic updates

答案 5 :(得分:1)

如果没有SIM卡,coarse location provider无法知道粗略位置,除非它能够找到由Google映射的WiFi网络。

请求最后的已知位置可能会导致过时的位置,因此相当无用。我猜这是上次某个应用程序请求更新位置时记录的位置。

我使用以下代码获取最近的位置:

    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_COARSE);
    criteria.setAltitudeRequired(false);
    criteria.setSpeedRequired(false);
    criteria.setBearingRequired(false);
    criteria.setCostAllowed(false);

    final LocationManager manager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

    ....
    LocationListener listener = new LocationListener() {
        @Override
        public void onLocationChanged(Location lastKnownLocation) {
                     ....
        }
        // rest of interface
     }


     manager.requestSingleUpdate(criteria, listener, null);

最后一次通话确保我们请求当前位置,而不是之前能够找到未知时间的位置。

您可能会尝试将其更改为Criteria.ACCURACY_FINE,以便启动GPS。请注意,如果GPS在相当长的时间内没有修复,可能需要几分钟才能实现修复。我同时期待您看到GPS图标,表明它正在等待修复。

答案 6 :(得分:1)

OnConnected方法有什么用?

在此方法中,您应创建LocationRequest优先级为PRIORITY_HIGH_ACCURACY的对象。

@Override
public void onConnected(Bundle dataBundle) {
    mLocationRequest = LocationRequest.create();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationClient.requestLocationUpdates(mLocationRequest, fusedListener);
}

答案 7 :(得分:1)

您需要做的就是像这样向请求对象添加优先级属性。

public void onConnected(Bundle arg0)
{
    locationrequest = LocationRequest.create();
    locationrequest.setInterval(1000);
    locationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationclient.requestLocationUpdates(locationrequest, this);
}

也许使用布尔变量让用户可以选择强制使用GPS

boolean forceGPS=false;
.
.
.//make the user choose to change the value of the boolean
.
.
public void onConnected(Bundle arg0)
    {
        locationrequest = LocationRequest.create();
        locationrequest.setInterval(1000);
        if(forceGPS==true)
        {
        locationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        }
        locationclient.requestLocationUpdates(locationrequest, this);
    }

答案 8 :(得分:0)

试试这个:

public final static int MINACCURACY = 50;

private LocationManager lm;
private LocationListener listener;

private void foundLoc(double x, double y) {
    // do something with x,y
    Log.v("DEBUG", x + "," + y);
}


public void findMe(View v) {
    lm = (LocationManager) getSystemService(LOCATION_SERVICE);
    listener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            if(location.getAccuracy() < MINACCURACY) {
                foundLoc(location.getLatitude(), location.getLongitude());
                lm.removeUpdates(listener);
            }
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onProviderDisabled(String provider) {
        }
    };
    lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 100, 0, listener);
}

MINACCURACY以米为单位。这样,在按下按钮(调用findMe方法)时,启用GPS,找到您的位置,精度最低,找到的方法是获取数据,侦听器终止(反过来禁用GPS)。

答案 9 :(得分:0)

我更喜欢使用实现LocationListener的服务来获取当前接近准确的位置。我通常采取以下步骤:

  1. LocationManager
  2. 中初始化requestLocationUpdates并致电GPS_PROVIDERNETWORK_PROVIDER onCreate()
  3. getLastKnownLocationGPS_PROVIDER致电NETWORK_PROVIDER,并使用getTime()了解最新的位置。
  4. 广播最后一个位置(如果它<30秒)(可选)
  5. 与此同时,当调用onLocationChanged时,我将新更新的位置与最后一个最佳位置(如果有)进行比较,并检查准确度。
  6. 如果准确度Δ<1。 MIN_ACCURACY(用户变量),将其用作最佳位置
  7. 广播当前最佳位置
  8. 必须删除LocationManager locationManager.removeUpdates(this);
  9. 调用stopSelf(); (您也可以停止活动onDestroy
  10. 的服务

    编辑:

    好的......上面的方法是使用Location API,下面我使用Fused Provider(GooglePlayServices)编码。我已经测试了我的Nexus 5(Android 4.4.2),没有SIM卡,没有WIFI ......而且我得到了结果。

    编辑2:我还测试了Android 2.3.3 LG Optimus(没有SIM卡和Wifi),并且花了大约5分钟来锁定(使用Fused Provide),但我立即获得了位置图标。

    public class HomeActivity extends FragmentActivity implements
            ActionBar.OnNavigationListener,
            GooglePlayServicesClient.ConnectionCallbacks,
            GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {
    
        private LocationClient locationClient;
        private LocationRequest locationRequest;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_home);
                // ...
                int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
            if (resp == ConnectionResult.SUCCESS) {
                locationClient = new LocationClient(this, this, this);
                locationClient.connect();
            } else {
                Toast.makeText(this, "Google Play Service Error " + resp,
                        Toast.LENGTH_LONG).show();
    
            }
        }
    
        @Override
        public void onConnected(Bundle connectionHint) {
            if (locationClient != null && locationClient.isConnected()) {
    
                locationRequest = LocationRequest.create();
                locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
                locationRequest.setInterval(100);
                locationClient.requestLocationUpdates(locationRequest, this);
    
            }
        }
    
        @Override
        public void onLocationChanged(Location location) {
    
            try {
                if (location != null) {
                    LatLng gps = new LatLng(location.getLatitude(), location.getLongitude());
                    Log.v("JD", "My Location: " + gps.toString());
                }
            } catch (Exception e) {
                Log.d("JD",
                        "onLocationChanged", e);
    
            }       
        }
    }
    

答案 10 :(得分:0)

这里有两件事让你有时会得到null,有时会得到一个位置。

首先,您要在LocationClient方法中创建onClick的新实例,该实例与您在connect()中调用onStart()的实例不同。这将产生不可预测的行为,有时客户端在从LocationClient.getLastLocation()返回结果之前有足够的时间进行连接,有时则不会。

其次,您应该通过拨打LocationClient.getLastLocation()来保护对LocationClient.isConnected()的呼叫。它在LocationClient.isConnected()文档中说明以下内容: https://developer.android.com/reference/com/google/android/gms/location/LocationClient.html#isConnected()

  

检查客户端当前是否已连接到该服务,以便对其他方法的请求成功。应用程序应该通过调用此方法来保护用户引起的客户端操作。

由于用户通过点击按钮触发onClick()代码,因此您应该在尝试获取最后一个位置之前调用此方法。

因此,您的代码应如下所示:

LocationClient mLocationClient;
Location mCurrentLocation;

@Override
protected void onCreate() {
    ...
    mLocationClient = new LocationClient(this, this, this);
    ...
}

@Override
protected void onStart() {
    mLocationClient.connect();
    super.onStart();
}

@Override
protected void onStop() {
    mLocationClient.disconnect();
    super.onStop();
}

public void onClick(View v) {
    ...
    if (mLocationClient.isConnected()) {
        // You should get a valid location here
        mCurrentLocation = mLocationClient.getLastLocation();
    }
}

这应该为LocationClient提供足够长的时间来连接并为您提供有效的位置,这应该包含GPS数据。

答案 11 :(得分:0)

由于没有人分享此链接,因此我发现这是最有用的文档http://developer.android.com/guide/topics/location/strategies.html

“您可能希望最新的位置修复是最准确的。但是,由于位置修复的准确性不同,最近的修复并不总是最好。您应该包含基于几个选择位置修复的逻辑标准也取决于应用和现场测试的使用情况。“

您最好的选择是,只要活动位于前台,就会保持位置监听器的运行,并在按下按钮时选择最准确的缓存位置。您可能需要显示微调器或其他内容,并在等待准确测量显示时禁用该按钮。