Приложение "Погода". Работа с геолокацией.

Урок 33 — Приложение "Погода". Работа с геолокацией.

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

Работа с LocationManager

Процесс получения координат в Android достаточно прост:

  1. Получаем LocationManager.
  2. Подписываемся на обновления координат.
  3. Когда координаты изменяются, LocationManager дёргает наш коллбэк.

LocationManager работает с так называемыми провайдерами, источниками, из которых система получает геоданные.

Существуют такие провайдеры:

  • GPS_PROVIDER — определяет координаты, используя спутники GPS.
  • NETWORK_PROVIDER — определяет координаты, используя мобильную и Wi-Fi сеть.
  • PASSIVE_PROVIDER — по сути не получает координаты сам, а лишь использует данные, полученные другими приложениями. Если никакие другие приложения при этом не получают обновлений координат, то и мы не получим.
  • FUSED_PROVIDER — специальный провайдер, который получает данные, используя все другие провайдеры сразу.

Получаем разрешение

Чтобы работать с геолокацией, нам потребуется соответствующее разрешение:

  • ACCESS_FINE_LOCATION — если нам нужны точные координаты (получаемые по GPS).
  • ACCESS_COARSE_LOCATION — если нам нужны примерные координаты (получаемые, например, по сети).

Добавьте разрешение в манифест:

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

Поскольку гео разрешения считаются опасными, на новых версиях Android придётся запросить Runtime Permission.

В MainActivity добавьте код:

/**
 * Проверяем, есть ли разрешение и запрашиваем его, если нет
 */
private void checkAndRequestGeoPermission() {
    int permissionCheck = ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION);

    if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                REQUEST_CODE_LOCATION_PERMISSION);
    } else {
        setupLocation();
    }
}

/**
 * Подписываемся на обновления гео
 */
private void setupLocation() {
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CODE_LOCATION_PERMISSION) {
        if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            setupLocation();
        } else {
            // Нет гео
            // Попробуем показать ещё раз
            checkAndRequestGeoPermission();
        }
    }
}

Этот код должен быть вам знаком, так как ранее мы уже запрашивали рантайм разрешения ранее: проверяем, есть ли разрешение, если есть — начинаем работать с гео, если нет — запрашиваем. В коллбэке результата запроса разрешения мы опять проверяем, получили ли разрешение, если нет — запрашиваем ещё раз, если да — начинаем работать с гео.

Вызовите метод checkAndRequestGeoPermission() в конце onCreate():

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

    setContentView(R.layout.activity_main);

    checkAndRequestGeoPermission();
}

Запрашиваем обновления гео

Итак, теперь начнём работу с геолокацией. Создайте приватное поле LocationManager:

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_LOCATION_PERMISSION = 0;

    private LocationManager locationManager;

Так же создадим LocationListener, методы которого будут вызываться, когда происходят какие-то изменения, касающиеся гео:

private final LocationListener locationListener = new LocationListener() {

    @Override
    public void onLocationChanged(Location location) {
        Log.v(TAG, "Location changed: " + location);
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        Log.v(TAG, "Status changed: " + provider + ", status: " + status);
    }

    @Override
    public void onProviderEnabled(String provider) {
        Log.v(TAG, "Provider enabled: " + provider);
    }

    @Override
    public void onProviderDisabled(String provider) {
        Log.v(TAG, "Provider disabled: " + provider);
    }

};

У него четыре метода:

  • onLocationChanged() — вызывается, когда изменяется геопозиция.
  • onStatusChanged() — вызывается, когда изменяется статус провайдера.
  • onProviderEnabled() — вызывается, когда один из провайдеров стал доступен.
  • onProviderDisabled() — вызывается, когда один из провайдеров стал недоступен.

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

В методе setupLocation() добавьте код:

locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

Criteria criteria = new Criteria();

При помощи класса Criteria мы можем указать параметры, по которым LocationManager подберёт подходящий провайдер. Нам достаточно дефолтных параметров, поэтому не будем настраивать критерии.

Теперь получим провайдер:


String bestProvider = locationManager.getBestProvider(criteria, true);

Первый параметр — критерий, который мы будем использовать. Второй параметр — должен ли метод производить подбор только среди включенных провайдеров. Нас не интересуют отключенные, поэтому передадим true.

Итак, этот метод найдёт доступные провайдеры, соответствующие переданным критериям, и вернёт лучший, сортируя по таким параметрам, как энергопотребление, точность и т.д.

Если же найти подходящий провайдер не выйдет, метод вернёт null.


Продолжение доступно на платных тарифах

Это недорого — всего от 440 ₽ в месяц!


ВЫБРАТЬ ТАРИФ


Продолжение доступно после регистрации

Все уроки на сайте доступны абсолютно бесплатно после регистрации.

Регистрация займёт меньше минуты ;)