Поставщик плавного местоположения, похоже, не использует приемник GPS

Android 4.3 на Moto G, Android 4.4.2 на Nexus 7 2012, Android 4.4.2 на Nexus 5. 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

В основной деятельности:

 //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 всегда равно null.

Я тестирую снаружи в нескольких местах всегда с ясным видом на небо. Я ждал три минуты в каждом месте.

Я никогда не вижу значок GPS на панели уведомлений Android в верхней части экрана.

У меня эти настройки местоположения: Введите описание изображения здесь

Приложение GPS Test позволяет использовать GPS в закрытом помещении на одном устройстве с отключенным Wi-Fi, поэтому GPS работает: Введите описание изображения здесь

Регистрация для обновлений местоположения, как на https://developer.android.com/training/location/receive-location-updates.html , также не работает. Зарегистрированный метод никогда не вызывался.

Что я делаю не так?

Solutions Collecting From Web of "Поставщик плавного местоположения, похоже, не использует приемник GPS"

Я решил это. Проблема заключалась в том, что «Разрешить приложениям Google доступ к вашему местоположению» было отключено: Введите описание изображения здесь

Когда я включаю его, я получаю показания GPS, и когда он отключается, я этого не делаю.

Я оставил его по двум причинам:

  1. Я разрабатываю приложение, которое будет использоваться для большого количества устройств в компании, и я хочу, чтобы минимальная ручная настройка была необходима

  2. На экране четко сказано: «Этот параметр влияет только на приложения Google». Я знаю, что Play Services – это программное обеспечение Google, но я не думал, что Google ожидает от конечного пользователя этого.

Затем я получил обновление Android 4.4.2, и изменилась страница настроек местоположения. Похоже, что я могу отключить Google Location Reporting и по-прежнему получать показания GPS от поставщика плавного доступа: Введите описание изображения здесь

Поэтому, возможно, Google поняла, что настройка была запутанной и улучшила ее. В любом случае, я бы сэкономил много времени, если бы получил 4.4.2 несколько дней назад.

Проблема заключается в getLastLocation() поскольку она использует кэшированное местоположение. У меня была та же проблема, что и я пытался использовать этот простой подход. Поскольку я переключился на прослушивание обновлений (и остановился после первого успешного обновления).

Это мой код, который работает.

Во-первых, проверка доступности в приложении (не обязательно, может быть в Деятельности и без сохранения результата):

 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, пока некоторые из клиентов не спросят (подписываются) о высокой точности местоположения (как описано в примерах, предоставленных другими пользователями). Приложение GPS test не использует провайдер местоположения, но использует старый «прямой» способ получения местоположения.

Также существует механизм истечения срока действия, который через некоторое время удаляет информацию о последнем местоположении, если считается, что он устарел.

Подводя итог всему выше, действительно возможно, что LP (поставщик местоположения) не имеет ничего вам дать.

Я думаю, что вы тестируете свое приложение в помещении, оно не работает.

И поток кода.

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

Согласно документам

Этот метод обеспечивает упрощенный способ получения местоположения. Он особенно хорошо подходит для приложений, для которых не требуется точное местоположение, и которые не хотят поддерживать дополнительную логику для обновлений местоположения.

Поэтому он может или не может возвращать высокоточное местоположение.

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

Может быть, использовать логическую переменную, чтобы у пользователя были возможности принудительно использовать 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 не имеет возможности узнать грубую позицию, если только он не может найти сеть Wi-Fi, которая была отображена Google.

Запрос последнего известного местоположения может привести к устаревшему местоположению и, как таковой, бесполезен. Я предполагаю, что это позиция, которая была записана в последний раз, когда какое-то приложение запросило обновление местоположения.

Для получения последнего местоположения я использую следующий код:

  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, указывающий, что он ждет исправления.

Что OnConnected метод OnConnected ?

В этом методе вы должны создать объект LocationRequest с приоритетом PRIORITY_HIGH_ACCURACY .

 @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 находится в метрах. Таким образом, при нажатии кнопки (которая вызывает метод findMe) GPS включен, ваше местоположение находится с минимальной точностью, метод foundLoc получает данные, а слушатель заканчивается (что, в свою очередь, отключает GPS).

Здесь происходят две вещи, которые заставляют вас иногда получать 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.

Поскольку никто не поделился этой ссылкой, я нашел, что это самая полезная документация http://developer.android.com/guide/topics/location/strategies.html

«Вы можете ожидать, что самое последнее исправление местоположения является самым точным. Однако, поскольку точность определения местоположения меняется, последнее исправление не всегда является лучшим. Вы должны включить логику для выбора исправлений местоположения на основе нескольких критериев. Критерии также варьируются в зависимости от вариантов использования приложения и полевых испытаний ».

Лучше всего держать приемника местоположения до тех пор, пока активность находится на переднем плане и выберите наиболее точное место в кеше при нажатии кнопки. Возможно, вам понадобится показать прядильщик или что-то еще, и отключите кнопку, пока она ждет точного измерения.

Я предпочитаю использовать Сервис, который реализует LocationListener чтобы получить текущее почти точное местоположение. Обычно я делаю следующие шаги:

  1. Инициализировать LocationManager и вызвать requestLocationUpdates для GPS_PROVIDER и NETWORK_PROVIDER в onCreate()
  2. Вызовите getLastKnownLocation для GPS_PROVIDER и NETWORK_PROVIDER и используйте getTime() чтобы узнать последнее более новое местоположение.
  3. Передача последнего местоположения (если оно менее 30 секунд) (необязательно)
  4. Тем временем, когда onLocationChanged я сравниваю недавно обновленное местоположение с последним лучшим местоположением (если оно есть) и проверяет уровень точности.
  5. Если точность delta <MIN_ACCURACY (пользовательская переменная), используйте ее как наилучшее местоположение
  6. Лучшее место для вещания
  7. Необходимо удалить LocationManager locationManager.removeUpdates(this);
  8. Вызов stopSelf (); (Вы также можете прекратить обслуживание из активности onDestroy )

РЕДАКТИРОВАТЬ:

OK … Выше был метод Location API, ниже я закодирован с использованием Fused Provider (GooglePlayServices). Я тестировал на своем Nexus 5 (Android 4.4.2), NO SIM, NO WIFI … и я получаю результаты.

Редактирование 2: Я также тестировал Android 2.3.3 LG Optimus (без SIM-карты и Wi-Fi), и потребовалось около 5 минут, чтобы получить блокировку (используя 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); } } }