Расчет Времени Заката И Восхода Солнца С Использованием Координат Устройства Android С Помощью Earthtools

Привет Хабр!

Расчет времени заката и восхода солнца с использованием координат устройства Android с помощью Earthtools

Однажды была поставлена задача разработать движок для расчета времени начала заката и рассвета на основе местоположения телефона.

Кроме того, чтобы облегчить себе работу, меня загрузили аномальными математическими формулами, из-за которых ничего не укладывалось в моей голове.

Итак, я решил поискать альтернативу этим адским формулам.

Покопавшись в Гугле, я нашел интересный сайт: http://www.earthtools.org/ .

Он предоставляет несколько веб-сервисов, связанных с работой с картами.

Одним из них был сервис, которому вы предоставляете в качестве входных данных широту, долготу и дату, а в ответ получаете xml со следующим содержимым:

Расчет времени заката и восхода солнца с использованием координат устройства Android с помощью Earthtools

Исходя из этого, задача значительно упрощается: 1. Получить координаты устройства; 2. Сгенерируйте GET-запрос; 3. Отправить запрос; 4. Получите ответ (наш XML); 5. Разобрать XML для получения необходимых данных; 6. Отобразите результат. Сразу предупрежу, что никакого хардкорного кода здесь не будет, а только простой движок.

Приступим, начнем с разрешений в AndroidManifest.xml.

  
  
  
   

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

Далее получаем координаты устройства.

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

Поскольку здесь нет супер-UI, а крайне маленький движок, поэтому у Activity есть только кнопка «Обновить», а под ней TextView для отображения результатов.

Я также удалил названия пакетов и импорта.



public class MainActivity extends ActionBarActivity implements View.OnClickListener { private TextView helloWorld; private Button update; private LocationListener locationListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initUI(); initLocationListener(); } private void requestLocationUpdate() { LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); List<String> allProviders = locationManager.getAllProviders(); for (String provider : allProviders) { helloWorld.append(provider + "\n"); } String bestProvider = locationManager.getBestProvider(createGPSCriteria(), true); helloWorld.append("Best: " + bestProvider + "\n"); locationManager.requestSingleUpdate(bestProvider, locationListener, null); } private void initLocationListener() { locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { Calendar calendar = Calendar.getInstance(); int day = calendar.get(Calendar.DATE); int month = calendar.get(Calendar.MONTH) + 1; SunAsyncTask sunAsyncTask = new SunAsyncTask(location.getLatitude(), location.getLongitude(), day, month); try { HttpResponse response = sunAsyncTask.execute().

get(); String stringEntity = EntityUtils.toString(response.getEntity()); SunXmlParser sunXmlParser = new SunXmlParser(stringEntity); helloWorld.append("Sunset: " + sunXmlParser.parse(SunXmlParser.SUNSET) + "\n"); helloWorld.append("Sunrise: " + sunXmlParser.parse(SunXmlParser.SUNRISE) + "\n"); } catch (Exception e) { e.printStackTrace(); } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } }; } private void initUI() { helloWorld = (TextView) findViewById(R.id.hello_world); update = (Button) findViewById(R.id.update); update.setOnClickListener(this); } private Criteria createGPSCriteria() { Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_LOW); criteria.setCostAllowed(false); return criteria; } @Override public void onClick(View clickedView) { int id = clickedView.getId(); if (id == R.id.update) { requestLocationUpdate(); } } }

Здесь мы сначала инициализируем UI, затем инициализируем LocationListener, который должен будет реагировать на изменение координат, а именно при изменении позиции он запустит AsyncTask, который сформирует запрос, отправит его и получит ответ. После инициализации нам необходимо выбрать провайдера, у которого мы будем брать широту и долготу нашего местоположения.

Здесь нет ничего сложного, есть готовый метод getBestProvider, который делает это по критериям, которые мы ему передаем в первом аргументе.

Критерии — это класс, в который мы помещаем параметры провайдера, которого хотим получить.

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

Ну и, соответственно, нажав кнопку Update у провайдера, мы запрашиваем обновление местоположения, на что LocationListener отвечает, вызывая AsynkTask, о котором я вам сейчас расскажу.



public class SunAsyncTask extends AsyncTask<Void, Void, HttpResponse> { private double latitude; private double longitude; private int day; private int month; public SunAsyncTask(double latitude, double longitude, int day, int month) { this.latitude = latitude; this.longitude = longitude; this.day = day; this.month = month; } private String createUrl() { // http://www.earthtools.org/sun/ <latitude>/<longitude>/<day>/<month>/<timezone>/<dst> StringBuilder stringBuilder = new StringBuilder(" http://www.earthtools.org/sun/ "); stringBuilder.append(String.valueOf(latitude)).

append("/"); stringBuilder.append(String.valueOf(longitude)).

append("/"); stringBuilder.append(String.valueOf(day)).

append("/"); stringBuilder.append(String.valueOf(month)).

append("/"); stringBuilder.append("99").

append("/"); stringBuilder.append("0"); Log.d("URL", stringBuilder.toString()); return stringBuilder.toString(); } @Override protected HttpResponse doInBackground(Void. params) { HttpResponse response = null; HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(createUrl()); try { response = client.execute(get); } catch (IOException e) { e.printStackTrace(); } return response; } }

Здесь тоже все просто.

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

Метод createUrl генерирует URL-адрес для запроса GET, но параметров здесь несколько больше, чем я писал ранее.

А именно: часовой пояс и летнее время.

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

Соответственно я поставил 99. Ну dst учитывает летнее время (0 - нет, 1 - да).

Итак, мы должны получить XML с результатом.

Теперь его нужно разобрать.

Мы будем использовать XmlPullParser как обычно; для тех, кто не знаком, советую с ним ознакомиться, так как он имеет ряд «особенностей».

Ну и, собственно, класс, который разбирает закат и восход солнца.



public class SunXmlParser { private String xmlString; private XmlPullParser parser; public static final String SUNRISE = "sunrise"; public static final String SUNSET = "sunset"; public SunXmlParser(String xmlString) throws XmlPullParserException { this.xmlString = xmlString; parser = Xml.newPullParser(); parser.setInput(new StringReader(xmlString)); } public void setXmlString(String xmlString) throws XmlPullParserException { this.xmlString = xmlString; } public String parse(String tag) throws XmlPullParserException, IOException { parser.setInput(new StringReader(xmlString)); int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { if(eventType == XmlPullParser.START_TAG && parser.getName().

equalsIgnoreCase(tag)) { parser.next(); return parser.getText(); } eventType = parser.next(); } return "Not found"; } }

Вот и все, собственно.

Проблема решена, результат на экране:

Расчет времени заката и восхода солнца с использованием координат устройства Android с помощью Earthtools

Теги: #Android #локация #закат #Восход #Разработка Android

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.