earthtoolsを使用して、Androidデバイスの座標で日没時間と夜明け時間を計算します

こんにちはHabr!



画像



一度、タスクは電話の位置に基づいて日没と日の出の開始時間を計算するためのエンジンを開発するように設定されました。



さらに、作業を容易にするために、異常な数式がロードされましたが、そこには頭の中に何も収まりません。 だから、私はこれらの地獄のような式の代替案を探すことにしました。



Googleを調べてみると、面白いサイトが見つかりました: http ://www.earthtools.org/。 マップの操作に関連するいくつかのWebサービスを提供します。 それらの1つは、緯度、経度、日付を入力するサービスであり、応答として次のコンテンツのxmlを取得します。







これに基づいて、タスクは大幅に簡素化されます。



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はありませんが、非常に小さなエンジンがあるため、アクティビティには[更新]ボタンのみがあり、その下に結果を表示する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メソッドがあります。 Criteriaは、取得するプロバイダーのパラメーターを配置するクラスです。 この例では、信号が悪くても「通常の」位置精度で動作する無料プロバイダーを選択するための基準を設定します。



さて、それに応じて、プロバイダーから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メソッドはGETリクエストのURLを生成しますが、以前に書いたよりも若干多くのパラメーターがあります。 すなわち:タイムゾーンとdst。 したがって、タイムゾーンではすべてが明確であるため、計算するタイムゾーンを指定できますが、タイムゾーンとして「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"; } }
      
      





実際、それがすべてです。 問題が解決され、画面に結果が表示されます。










All Articles