Подтвердить что ты не робот

Поставщик с плавным местоположением, похоже, не использует приемник 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 в верхней части экрана.

У меня эти настройки местоположения: enter image description here

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

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

Что я делаю неправильно?

4b9b3361

Ответ 1

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

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

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

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

  • На экране четко сказано: "Этот параметр влияет только на приложения Google". Я знаю, что Play Services - это программное обеспечение Google, но я не думал, что Google ожидает, что конечный пользователь это поймет.

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

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

Ответ 2

Проблема заключается в 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;
    }
  }
}

Затем, на Activity:

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

Надеюсь, это поможет вам заставить его работать!

Ответ 3

Поставщик местоположений не пробуждает GPS, пока некоторые из клиентов не спросят (подписываются) о местоположении высокой точности (как описано в примерах, предоставленных другими пользователями). Приложение GPS test не использует провайдера местоположения, но использует старый "прямой" способ получения местоположения.

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

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

Ответ 4

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

и поток кода.

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

Ответ 5

В соответствии с документами

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

чтобы он мог или не мог вернуть высокоточное местоположение.

GPS может занять некоторое время, чтобы заблокировать, поэтому вызов getLastLocation может или не может вернуть местоположение

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

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

что вы должны делать, в вашем onConnected получить последнее место там, например

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

как сказано в этом примере onConnected is 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

Ответ 6

Без SIM-карты coarse location provider не имеет возможности узнать грубую позицию, если только она не может найти сеть WiFi, которая была отображена 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, указывающий, что он ждет исправления.

Ответ 7

Что в методе OnConnected?

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

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

Ответ 8

Все, что вам нужно сделать, это добавить свойство приоритета к объекту запроса, подобному этому.

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

Ответ 9

Попробуйте следующее:

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

Ответ 10

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

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

EDIT:

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

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

        }       
    }
}

Ответ 11

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

Ответ 12

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

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

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