融合的位置提供商似乎不使用GPS接收器

Moto G上的Android 4.3,Nexus 7 2012上的Android 4.4.2,Nexus 5上的Android 4.4.2。

我不想收到定期的位置更新,我只是想要一个准确的位置,当用户按下button。

我已经按照这个例子: 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卡。 如果我启用无线networking有时我得到一个准确的位置。 其他时间mCurrentLocation为空。

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

我在外面的几个地方总是清楚地看到天空。 我在每个地方等了三分钟。

我从来没有看到GPS图标出现在屏幕顶部的Android通知栏上。

我有这些位置设置: 在这里输入图像说明

一个GPStesting应用程序设法使用GPS在室内成功地在同一个设备与Wi-Fi禁用,所以GPS正在工作: 在这里输入图像说明

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

我究竟做错了什么?

我解决了它。 问题是“让Google应用程序访问您的位置”已closures: 在这里输入图像说明

当我打开它,我得到GPS读数,当它closures时,我不知道。

我已经离开了有两个原因:

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

  2. 屏幕上清楚地显示“此设置仅影响Google应用程序”。 我知道Play服务是Google软件,但我并不认为Google会希望最终用户了解这一点。

然后,我得到了Android 4.4.2更新和位置设置页面已经改变。 看起来,我可以closuresGoogle位置报告function,仍然可以从融合位置信息提供商获取GPS读数: 在这里输入图像说明

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

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

这是我的代码,工程。

首先,在应用程序中检查可用性(不是必需的,可以在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; } } } 

我希望这会帮助你把它工作!

位置提供者不会唤醒GPS,除非有些客户询问(订阅)高精度位置(如其他用户给出的示例中所述)。 GPStesting应用程序不使用位置提供程序,而是使用旧的“直接”获取位置的方式。

此外,还有终止机制,如果被认为是陈旧的,它会在一段时间之后去除关于上次定位的信息。

总而言之,LP(位置提供商)真的可能没有什么可以给你的。

我认为你正在室内testing你的应用程序,这是行不通的。

和代码stream

 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; } 

根据文件

这个方法提供了一个获取位置的简单方法。 它特别适用于不需要精确位置的应用程序,也不希望为位置更新维护额外的逻辑。

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

全球定位系统可能需要一段时间locking,所以调用getLastLocation可能会或可能不会返回一个位置

你最好要求位置更新,然后你得到一个位置只是停止请求位置更新。

同样看着你提供的代码,你是否在等待LocationClient连接,然后尝试获取一个位置? 这肯定会给你一个空的位置,因为它没有连接到位置呢。

你应该做的是在你的onConnected得到最后的位置,例如

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

正如它在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那样,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 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

你所要做的就是像这样向请求对象添加一个优先级属性。

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

也许使用一个布尔variables让用户有select强制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); } 

没有SIM卡, coarse location provider无法知道粗略的位置,除非它能够findGoogle已经映射的WiFinetworking。

请求最后一个已知的位置可能会导致过时的位置,因此是无用的。 我想这是上次某个应用请求位置更新时logging的位置。

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

  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); 

最后的呼叫确保我们请求当前的位置,而不是它能够find以前未知的时间的位置。

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

OnConnected方法中有什么?

在这个方法中,你应该创buildPRIORITY_HIGH_ACCURACY优先级的LocationRequest对象。

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

尝试这个:

 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以米为单位。 这样,在按下button(调用findMe方法)时,启用GPS,以最小的准确度find您的位置,方法foundLoc获取数据,并且监听器终止(反过来,禁用GPS)。

有两件事情在这里,导致你有时得到null ,有时得到一个位置。

首先,你正在onClick方法中创build一个LocationClient的新实例,它与onStart()调用connect()实例不是同一个实例。 这将创build不可预知的行为,有时客户端将有足够的时间连接,然后从LocationClient.getLastLocation()返回结果,有时不会。

其次,您应该通过调用LocationClient.getLastLocation()来防止对LocationClient.getLastLocation()的调用。 它在LocationClient.isConnected()文档中说明了以下内容: https : //developer.android.com/reference/com/google/android/gms/location/LocationClient.html#isConnected()

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

由于用户通过点击button来触发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数据。

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

“你可能认为最近的定位是最准确的,但是由于定位的准确性不同,所以最近的定位并不总是最好的,你应该根据几个标准包含select定位的逻辑。标准也取决于应用和现场testing的使用情况。“

最好的办法是只要活动位于前台就保持位置侦听器,并在按下button时select最准确的caching位置。 您可能需要显示一个微调或其他东西,并在等待准确测量显示时禁用该button。

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

  1. 初始化LocationManager并为onCreate() GPS_PROVIDERNETWORK_PROVIDER调用requestLocationUpdates
  2. GPS_PROVIDERNETWORK_PROVIDER调用getLastKnownLocation ,并使用getTime()来了解最新的位置。
  3. 广播最后的位置(如果<30秒)(可选)
  4. 与此同时,当onLocationChanged被调用时,我将最近更新的位置与最后的最佳位置(如果有的话)进行比较,并检查准确度级别。
  5. 如果准确性增量<MIN_ACCURACY(用户variables),则将其用作最佳位置
  6. 广播当前最佳位置
  7. 必须删除LocationManager locationManager.removeUpdates(this);
  8. 呼叫stopSelf(); (你也可以停止活动的onDestroy服务)

编辑:

好的…上面的方法是使用Location API,下面我使用Fused Provider(GooglePlayServices)进行了编码。 我已经testing了我的Nexus 5(Android 4.4.2),没有SIM,没有WIFI …,我正在得到结果。

编辑2:我也testing了Android 2.3.3 LG Optimus(没有SIM&Wifi),花了大约5分钟locking(使用Fused Provided),但是我正在获取位置图标。

 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); } } }