Comment obtenir l'adresse de localisation dans une application Android
Dans tutoriels précédents, nous avons discuté la façon d'obtenir les données de localisation, ainsi que l'utilisation des données de localisation pour mettre en œuvre un système de suivi de localisation de dispositif simple en utilisant l'API ThingSpeak. Pour ce tutoriel, nous allons utiliser le Geocoder classe de traduire une adresse donnée dans sa latitude et de longitude (valeurs de géocodage), et traduit également une latitude et une valeur de longitude dans une adresse (géocodage inversé).
Préparation
De Wikipédia, Géocodage utilise une description d'un lieu, comme une adresse ou lieu postal, de trouver les coordonnées géographiques. Géocodage inverse, d'autre part, utilise les coordonnées géographiques pour trouver une description de l'emplacement.
Un géocodeur est soit un morceau de logiciel ou un service qui met en œuvre un processus de géocodage. L'API Android contient une classe Geocoder qui peut utiliser soit un nom de lieu ou latitude et de longitude les valeurs d'un emplacement pour obtenir plus de détails sur une adresse (il peut effectuer à la fois avant et géocodage inversé). Les détails de l'adresse de retour comprennent le nom de l'adresse, le nom du pays, le code du pays, code postal et plus.
App Disposition
Notre application va utiliser à la fois avant et géocodage inversé pour obtenir l'adresse de l'emplacement, et la mise en page de l'application est le reflet. La mise en page contient deux EditTexts pour Latitude et Longitude respectivement, et un EditText pour le nom de l'adresse entrée. Sous ceux-ci, nous avons deux RadioButtons, pour sélectionner si nous sont aller chercher une adresse en utilisant les valeurs de latitude / longitude de la localisation, ou en utilisant le nom de l'adresse. Il ya un bouton, qui commence la recherche de géocodage quand on clique dessus, un ProgressBar, montrer à l'utilisateur que la tâche de recherche est en cours d'exécution en arrière-plan, et un TextView pour montrer le résultat obtenu.
lt;? xml version = "1.0" encoding = "utf-8">
Obtention de l'adresse
Geocoder dispose de deux méthodes permettant de récupérer une adresse, getFromLocation (), qui utilise la latitude et la longitude, et getFromLocationName (), qui utilise le nom de l'emplacement. Les deux méthodes retourne une liste de Adresse objets. Une adresse contient des informations comme le nom d'adresse, pays, latitude et longitude, tandis que Emplacement contient latitude, longitude, relèvement et d'altitude entre autres. Rappelez-vous que les méthodes de Geocoder-dessus du bloc de l'filetage elles sont exécutées dans, et ne devraient jamais être appelé depuis le thread d'interface utilisateur de l'application.
Pour effectuer une tâche à long courir dans le fond, nous pouvons utiliser un AsyncTask. Cependant, le AsyncTask est pas recommandé pour des opérations telles que la recherche de géocodage, car il peut prendre un potentiellement beaucoup de temps pour revenir. AsyncTask de doit être utilisé pour des opérations relativement courtes. Alors que nous pouvons (et a) utiliser le AsyncTask, selon les recommandations de développeurs Android et les meilleures pratiques, nous aimerions utiliser un IntentService. Un IntentService étend service, et exécuté dans les opérations, il peut prendre aussi longtemps que nécessaire. Un IntentService détient aucune référence à l'activité qui l'a démarré, et ainsi, l'activité peut être reconstruit (comme lorsque le dispositif est mis en rotation), sans affecter les tâches de l'IntentService, contrairement à la AsyncTask. (NB: Nous avons en fait utilisé un AsyncTask, et il a travaillé aussi bien En bonus, l'activité, en utilisant un AsyncTask est. disponible dans le github projet MainActivityWithAsyncTask)
Utilisation de la IntentService
Nous étendons IntentService et définissons GeocodeAddressIntentService. Un IntentService est commencé un peu comme une activité. Nous construisons une intention, et démarrer le service en appelant la méthode Context.startService ().
Avant de définir la classe, nous incluons notre GeocodeAddressIntentService dans le AppManifest. Ne pas oublier d'inclure également la permission INTERNET. Dans mon cas, tout en développant / essais sur un dispositif Nexus 5 Lollipop, le réseau appelle simplement silencieusement échoué avant, y compris l'autorisation d'INTERNET. Donc, si vous ne recevez pas de réponse, vérifiez d'abord que vous avez demandé la permission INTERNET.
Pour utiliser notre IntentService, nous devons mettre en œuvre la méthode onHandleIntent (Intention). Ceci est le point d'entrée de IntentService, un peu comme le onCreate () est le point de l'activité de l'entrée. Dans l'extrait de code ci-dessous, prendre connaissance de l'objet de ResultReceiver. Lorsque votre IntentService a terminé cette tâche, il devrait avoir un moyen d'envoyer les résultats à l'invocation activité. Voilà où le ResultReceiver arrive, et nous en discuterons est mise en œuvre dans un peu.
GeocodeAddressIntentService public class étend IntentService {protected static final TAG ResultReceiver resultReceiver-privé String = "FetchAddyIntentService" de GeocodeAddressIntentService -Santé () {super ("GeocodeAddressIntentService") -} ... @ onHandleIntent vide Overrideprotected (intention Intention) {Geocoder de géocodage = new Geocoder (cela, Locale.getDefault ()) - Liste adresses = null-resultReceiver = intent.getParcelableExtra (Constants.RECEIVER) -int fetchType = intent.getIntExtra (Constants.FETCH_TYPE_EXTRA, 0) -...}}
L'extrait de code ci-dessous contient les énoncés prospectifs réelle ou géocodage inversé appels de recherche. Nous déterminons si la recherche utilise le nom du lieu, ou de localisation des valeurs de latitude / longitude, et d'appeler la méthode appropriée. Si vous utilisez le nom du lieu, nous appelons la méthode Geocoder.getFromLocationName (), et si vous utilisez latitude / longitude, que nous appelons Geocoder.getFromLocation méthode (). Vous pouvez spécifier un nombre maximum d'adresses à être retourné. Dans notre échantillon, nous demandons pour un maximum de un (1) adresse. Notez que le nom d'une adresse peut se référer à plus d'un endroit, répartis sur plusieurs pays. Dans une application de production, vous voudrez peut-être pour aller chercher plus d'un, et d'avoir un algorithme de déterminer qui est l'adresse la plus probable nécessaire.
si (== fetchType Constants.USE_ADDRESS_NAME) {String nom = intent.getStringExtra (Constants.LOCATION_NAME_DATA_EXTRA) -Essayez {adresses = geocoder.getFromLocationName (nom, 1) -} catch (IOException e) {errorMessage = "Service non disponible" - Log.e (TAG, errorMessage, e) -}} else if (fetchType == Constants.USE_ADDRESS_LOCATION) {location location = intent.getParcelableExtra (Constants.LOCATION_DATA_EXTRA) -Essayez {adresses = geocoder.getFromLocation (location.getLatitude (), location.getLongitude (), 1) -} catch (IOException ioException) {errorMessage = "Service non disponible" -Log.e (TAG, errorMessage, ioException) -} catch (IllegalArgumentException IllegalArgumentException) {errorMessage = "Latitude Longitude ou incorrecte a été utilisée "(. -Log.e TAG, errorMessage +" "+" Latitude = "+ location.getLatitude () +", Longitude = "+ location.getLongitude (), IllegalArgumentException) -}} else {errorMessage =" Inconnu " -} if (adresses == null || addresses.size () == 0) {if (errorMessage.isEmpty ()) {errorMessage = "Not Found" -} deliverResultToReceiver (Constants.FAILURE_RESULT, errorMessage, null) -} else {for (adresse Adresse: adresses) {String outputAddress = "" -pour (int i = 0 à i lt; address.getMaxAddressLineIndex () - i ++) {outputAddress + = "---" + address.getAddressLine (i) -}} adresse Adresse = addresses.get (0) -ArrayListaddressFragments = new ArrayList (), par (int i = 0 à i lt; address.getMaxAddressLineIndex () - i ++) {addressFragments.add(address.getAddressLine(i))-}(R.string.address_found))-deliverResultToReceiver(Constants.SUCCESS_RESULT,TextUtils.join(System.getProperty("line.separator"),addressFragments), adresse)-}
deliverResultToReceiver est une méthode simple, qui gère le retour des résultats de l'opération à l'invocation activité, à travers la ResultReceiver.
deliverResultToReceiver private void (int resultCode, String message, adresse Adresse) {paquet bundle = new Bundle () - bundle.putParcelable (Constants.RESULT_ADDRESS, adresse) -bundle.putString (Constants.RESULT_DATA_KEY, message) -resultReceiver.send (resultCode, paquet)-}
Nous avons mis l'ResultReceiver comme une classe interne dans le MainActivity.
AddressResultReceiver de classe étend ResultReceiver {AddressResultReceiver publique (gestionnaire Handler) {super (gestionnaire) -} @ onReceiveResult vide Overrideprotected (int resultCode, finale Bundle resultdata) {if (resultCode == Constants.SUCCESS_RESULT) {adresse Adresse finale = resultData.getParcelable (Constantes .RESULT_ADDRESS) -runOnUiThread (nouvelle Runnable () {void runOverridepublic () {progressBar.setVisibility (View.INVISIBLE) -infoText.setText ("Latitude:" + address.getLatitude () + "Longitude +" n ": "+ address.getLongitude () +" n "+" Adresse: "+ resultData.getString (Constants.RESULT_DATA_KEY)) -}}) -} else {runOnUiThread (nouvelle Runnable () {void runOverridepublic () {progressBar.setVisibility(View.INVISIBLE)-infoText.setText(resultData.getString(Constants.RESULT_DATA_KEY))-}})-}}
Démarrage du IntentService est assez similaire au démarrage d'une nouvelle activité. Nous construisons une intention, mettre dans les Extras nécessaires, et appelons Context.startService (Intention). Les Extras Nous associons dans l'intention est dépendant si nous effectuons une recherche avant ou arrière.
public void onButtonclicked (Voir vue) {intention d'Intention = new intention (ce, GeocodeAddressIntentService.class) -intent.putExtra (Constants.RECEIVER, mResultReceiver) -intent.putExtra (Constants.FETCH_TYPE_EXTRA, fetchType) -Si (fetchType == constantes. USE_ADDRESS_NAME) {if (addressEdit.getText () length () == 0) {Toast.makeText (this, "S'il vous plaît entrer un nom d'adresse", Toast.LENGTH_LONG) .Show () -. Retour-} intent.putExtra (Constantes . .LOCATION_NAME_DATA_EXTRA, addressEdit.getText () toString ()) -..} else {if (latitudeEdit.getText () length () == 0 || longitudeEdit.getText () length () == 0) {Toast.makeText (cela, "S'il vous plaît entrer Latitude / valeurs de longitude", Toast.LENGTH_LONG) .montrer () - Retour-} location location = new Location("")-location.setLatitude(Double.parseDouble(latitudeEdit.getText().toString()))-location.setLongitude(Double.parseDouble(longitudeEdit.getText().toString()))-intent.putExtra(Constants.LOCATION_DATA_EXTRA, emplacement) -} progressBar.setVisibility (View.VISIBLE) -Log.e (TAG, "Démarrage du service") - startService (intention) -}
Conclusion
Alors qu'il est très bien suivi l'emplacement d'un utilisateur, pour votre application pour étonner vraiment, montrant utilisateurs un nom d'adresse pour un lieu donné sera presque toujours plus utile que les valeurs de latitude et de longitude correspondantes.
Le code source complet est disponible sur GitHub, et peut être fourchue, téléchargé, copié et utilisé comme souhaité.
Si vous avez suivi nos précédents tutoriels sur en utilisant l'API ThingSpeak pour suivre l'emplacement d'un dispositif, et comment obtenir et utiliser l'emplacement d'un appareil Android, essayer d'intégrer le géocodage et obtenir adresse de l'emplacement dans les deux applications. Avoir codage amusant, et partager vos défis et les réussites dans les commentaires ci-dessous.