• 30 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 1/13/20

TP : Créez une application géolocalisée qui affiche des photos

Log in or subscribe for free to enjoy all this course has to offer!

Dans ce chapitre, nous proposons de réaliser une application géolocalisée qui affiche une photo à partir des coordonnées détectées par l'appareil et qui la télécharge depuis Flickr. Il va donc falloir mettre en œuvre les notions vus aux parties précédentes à savoir :

  • récupérer les coordonnées géographiques de l'appareil ;

  • réaliser une requête HTTP dans une tâche asynchrone vers Flickr pour trouver des photos géolocalisées ;

  • interpréter l'objet JSON reçu ;

  • réaliser une requête HTTP pour récupérer l'image depuis Flickr ;

  • afficher l'image.

Étape 1 : récupérez les coordonnées géographiques

Générez un nouveau projet Android Studio. Créez l'interface graphique minimale suivante qui comporte :

  • un bouton "Get coordinates"

  • 4 TextView :

    • Un TextView "Latitude"

    • Un TextView "-" ayant pour id "lat"

    • Un TextView "Longitude"

    • Un TextView "-" ayant pour id "lon"

Ajoutez-les à votre gabarit de façon à obtenir quelque chose ressemblant à :

Ajoutez au Manifest, les permissions :

  • ACCESS_FINE_LOCATION

  • ACCESS_COARSE_LOCATION

Dans votre activité, vérifiez que ces permissions sont présentes :

if ( ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED )

Si elles ne le sont pas, les demander à l'utilisateur :

ActivityCompat.requestPermissions( this, new String[] { android.Manifest.permission.ACCESS_COARSE_LOCATION }, 48 );

Toujours dans votre activité, afin d'activer le GPS et la détection de la position, créez un écouteur ne réalisant aucune opération et demandant à être notifié de mises à jour de votre position GPS :

// Acquire a reference to the system Location Manager
LocationManager locationManager = (LocationManager) this.getSystemService(this.LOCATION_SERVICE);
// Define a listener that responds to location updates
if (locationManager != null) {
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
public void onProviderEnabled(String provider) {
}
public void onProviderDisabled(String provider) {
}
};
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}

Nous allons maintenant réaliser le code du bouton, qui va lire la position courante. Surchargez l’événement de click de votre bouton :

Button b1 = (Button)findViewById(R.id.getcoordinate);
b1.setOnClickListener(new LocationOnClickListener(this));

 Codez alors la récupération des coordonnées dans votre classe LocationOnClickListener  :

class LocationOnClickListener implements View.OnClickListener {
private MainActivity mainActivity;
public LocationOnClickListener(MainActivity mainActivity) {
this.mainActivity = mainActivity;
}
@Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= 23 &&
ContextCompat.checkSelfPermission(mainActivity, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(mainActivity, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
// TODO: get the coordinates
// and record them in TextViews lat and lon
} else {
Log.i("CIO", "Permissions denied. SDK_INT=" + Build.VERSION.SDK_INT);
Log.i("CIO", "ACCESS_COARSE_LOCATION: " + ContextCompat.checkSelfPermission(mainActivity, android.Manifest.permission.ACCESS_COARSE_LOCATION));
Log.i("CIO", "ACCESS_FINE_LOCATION: " + ContextCompat.checkSelfPermission(mainActivity, android.Manifest.permission.ACCESS_FINE_LOCATION));
Log.i("CIO", "PackageManager.PERMISSION_GRANTED=" + PackageManager.PERMISSION_GRANTED);
}
}
}

À partir de là, vous devez obtenir l'affichage de vos coordonnées dans votre activité.

Étape 2 : requête HTTP géolocalisée vers Flickr

Étudier et comprendre l'API Flickr

Pour réaliser vos requêtes, il va falloir comprendre plus en profondeur l'API de Flickr, et non pas simplement utiliser une source publique non authentifiée comme au chapitre précédent. Ici, pour réaliser nos requêtes géolocalisées, il va falloir utiliser l'API flickr.photos.search. Parcourez la documentation, vous constaterez que :

  • api_key est requis : il s'agit d'un token d'autorisation, associé à votre identité qui vous autorise à interroger Flickr. Il va donc falloir créer un compte Flickr et générer ce code d'accès.

  • has_geo vous permet de filtrer les photos ayant une géolocalisation.

  • lat précisera la latitude.

  • lon précisera la longitude.

  • per_page permet de limiter le nombre de photos dans la réponse (1 seule suffira).

  • format permettra de préciser le format de la réponse, à savoir JSON.

On aura donc des requêtes qui seront du type :

https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=xxx&has_geo=1&lat=47.081987&lon=2.415535&per_page=1&format=json

Pour obtenir votre api_key, il faut vous rendre à la page de création d'une API key. Suivez la procédure jusqu'à votre obtenir votre clef. Testez l'URL précédente en substituant la clef "xxx" par votre clef. Vous devriez obtenir une réponse de l'API du type :

jsonFlickrApi({"photos":{"page":1,"pages":10405,"perpage":1,"total":"10405","photo":[{"id":"34158164013","owner":"68440732@N06","secret":"48f881beed","server":"4275","farm":5,"title":"les bou\u00e9es","ispublic":1,"isfriend":0,"isfamily":0}]},"stat":"ok"})

Réalisez la requête HTTP

Ajoutez au Manifest, la permission INTERNET.

En vous inspirant de la classe vu dans le chapitre précédent (AsyncFlickrJSONData), il vous faut réaliser la requête HTTP.

  1. Créez la classe AsyncFlickrJSONData  qui hérite deAsyncTask<String, Void, JSONObject>.

  2. Dans doInBackground(String... strings), réalisez la requête HTTP et reconstruisez la String à partir du flux du message.

  3. Reconstruisez l'objet JSON correspondant et renvoyez-le comme résultat dedoInBackground.

  4. DansonPostExecute(JSONObject j), affichez l'objet JSON dans le log, avec :

Log.i("CIO", "JSON data:" + j);

Démarrez votre requête dans un nouveau bouton

Créez un nouveau bouton "Get Image" qui va permettre de démarrer votre requête HTTP :

Dans le code de ce nouveau bouton, créez votre tâche asynchrone et exécutez-la :

String lat = ((TextView)mainActivity.findViewById(R.id.lat)).getText().toString();
String lon = ((TextView)mainActivity.findViewById(R.id.lon)).getText().toString();
String url = new String("https://api.flickr.com/services/rest/?method=flickr.photos.search" +
"&api_key=xxx" +
"&has_geo=1&lat=" + lat + "&lon=" + lon + "&per_page=1&format=json");
AsyncFlickrJSONData task = new AsyncFlickrJSONData(mainActivity);
task.execute(url);

Testez votre application. Vous devriez obtenir dans le logcat la sortie :

CIO: JSON data:{"photos":{"page":1,"pages":113,"perpage":1,"total":"113","photo":
[{"id":"18004255996","owner":"23924262@N04","secret":"0b5c2f2b2e",
"server":"7797","farm":8,"title":"DSC_0047","ispublic":1,
"isfriend":0,"isfamily":0}]
},"stat":"ok"}

Étape 3 : interprétez l'objet JSON

 Il vous faut maintenant extraire certaines informations nécessaires de cet objet JSON afin de pouvoir télécharger l'image depuis Flickr. Pour comprendre ce qui est important dans cet objet, il faut se référer encore une fois à la documentation de Flickr qui parle des URLs des photos. Ces URLs sont de la forme:

https://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}.jpg

Il vous faut donc extraire de votre objet JSON :

  • farm-id à partir de la clef farm ;

  • server-id à partir de la clef server ;

  • id à partir de la clef id ;

  • secret à partir de la clef secret.

Dans onPostExecute(JSONObject j)  de la classe AsyncFlickrJSONData, récupérez ces informations à partir de votre objet JSON. Puis, à des fins de debug, affichez-les dans le logcat :

Log.i("CIO", "farm: " + farm);
Log.i("CIO", "server: " + server);
Log.i("CIO", "id: " + id);
Log.i("CIO", "secret: " + secret);

Vous devriez obtenir une sortie qui ressemble à :

CIO: farm: 8
CIO: server: 7797
CIO: id: 18004255996
CIO: secret: 0b5c2f2b2e

Étape 4 : réalisez la requête HTTP pour obtenir l'image

Nous allons maintenant pouvoir récupérer l'image.

Adaptez la classe AsyncBitmapDownloader  vue dans le chapitre précédent afin de réaliser votre classe AsyncBitmapDownloader  qui hérite de AsyncTask<String, Void, Bitmap>  et qui sera chargée de télécharger l'image. La méthode Bitmap doInBackground(String... strings)  doit télécharger l'image et renvoyer un objetBitmap  :

URL url = null;
HttpURLConnection urlConnection = null;
Bitmap bm = null;
url = new URL(strings[0]);
Log.i("CIO", "Downloading " + url);
urlConnection = (HttpURLConnection) url.openConnection(); // Open
InputStream in = new BufferedInputStream(urlConnection.getInputStream()); // Stream
bm = BitmapFactory.decodeStream(in);
in.close();
return bm;

Puis, dans la méthode onPostExecute(JSONObject j) de la classe AsyncFlickrJSONData, il vous faut démarrer cette nouvelle tâche avec l'URL correcte et construite à partir des informations précédemment récupérées (farm, server, id, secret) :

protected void onPostExecute(JSONObject j) {
// Build the url of type https://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}.jpg
// from your JSONObject j
// TODO:
String url = ...
AsyncBitmapDownloader task2 = new AsyncBitmapDownloader(myActivity);
task2.execute(url);

À ce stade, lorsque vous cliquez sur le bouton "Get Image" vous devriez voir passer dans le log :

Downloading https://farm8.staticflickr.com/7797/18004255996_0b5c2f2b2e.jpg

Étape 5 : affichez l'image !

Il ne reste plus qu'à afficher l'image...

Pour se faire, ajoutez un ImageView  à votre interface graphique avec pour id "image". Puis, dans la méthode onPostExecute(Bitmap bitmap)  de AsyncBitmapDownloader, récupérez l'ImageView  de l'id "image" et modifiez cette image en appelant la méthode setImageBitmap().

Testez votre application...

Success !!! :D

(crédit photo: Guillaume CC-BY)
(crédit photo: Guillaume CC-BY)
Example of certificate of achievement
Example of certificate of achievement