📜 ⬆️ ⬇️

Calculating the time of sunset and sunrise on the coordinates of the Android device using earthtools

Hi Habr!

image

Once, the task was to develop an engine for calculating the start time of dusk and dawn, based on the location of the phone.
')
In addition, in order to facilitate the work, I was loaded with anomalous mathematical formulas, from which nothing fit in my head. So, I decided to look for an alternative to these hellish formulas.

Having rummaged in Google, I found an interesting site: http://www.earthtools.org/ . It provides several web services related to working with maps. One of them was the service, which you give to the input latitude, longitude and date, and as a response you get the xml of the following content:



Based on this, the task is much simpler:

1. Get device coordinates;
2. To form a GET request;
3. Submit a request;
4. Get the response (our XML);
5. Parse XML to get the necessary data;
6. Display the result.

I will immediately warn you that there will be no hardcore code here, just a simple engine.

Getting started, to start the resolution in 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" /> 


Next we get the coordinates of the device. I note right away that the exact coordinates in practice are absolutely not needed for tasks of this kind, so you can even use the coordinates that the cellular network gives us. Since there is no super UI, but an extremely small engine, so the Activity has only the Update button, and below it is a TextView to display the results. I also removed the names of the package and import.

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

Here, we first initialize the UI, then initialize the LocationListener, which will have to respond to the change of coordinates, namely when the position changes, it will launch AsyncTask, which will generate the request, send it and receive a response.

After initialization, we need to choose a provider from which we will take the latitude and longitude of our location.

There is nothing complicated here; there is a ready-made method getBestProvider, which does this according to the criteria that we pass to it in the first argument. Criteria is the class in which we put the parameters of the provider we want to receive. In this example, I set the criterion for selecting a free provider that would work even with a bad signal and with “normal” positioning accuracy.

Well and, accordingly, by pressing the Update key from the provider, we request an update of the location to which LocationListener responds, calling AsynkTask about which I will tell you now.

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

Here, too, everything is simple. Let me remind you, as I have already said, to obtain time, you need the coordinates and date of the day of sunset and dawn, which we want to receive.

The createUrl method generates a URL for a GET request, but there are a few more parameters than I wrote before. Namely: timezone and dst. So, everything is clear with the timezone, you can specify the time zone in which you want to calculate, but if you substitute "99" as a time zone, then it will be automatically determined based on the coordinates that you transmit. Accordingly, I set 99. Well, dst is the accounting for summer time (0 - no, 1 - yes).

So, it is assumed that we get the XML with the result. Now it needs to be parsed. We will use as usual XmlPullParser, who is not familiar, I advise you to read, as it has a number of "features". Well, in fact, the class that parsit sunset and sunrise.

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

That's all. Problem solved, the result on the screen:

Source: https://habr.com/ru/post/248539/


All Articles