Tutoriels Android

Map application pour Android SDK 1.5, deuxième partie

André vous proposait récemment de découvrir les fonctionnalités maps offertes par la version 1.5 du SDK Android, voici la suite de ce tutoriel. La troisième partie est déjà en route !

Mon premier tutoriel présentait les bases d’une application Android et Google Maps élémentaire.

Ce deuxième tutoriel va présenter les notions de map overlay, de géolocalisation et de client http. Pour cela nous présenterons une solution de recherche de services basées sur Yahoo Search API et par la même occasion cela donnera un exemple d’utilisation de REST API avec Android.

NB : Yahoo Search ne fonctionne qu’aux US pour l’instant, placez donc votre emulateur au dessus des US avec un geo fix approprié.

La license de Yahoo Search ne permet pas son utilisation a des fins commerciales.

Dans un prochain tutoriel nous utiliserons Google Search et n’aurons pas ces limitations.

Pour la réalisation du client REST (Representational State Transfer) nous utiliserons la librairie HttpClient. Dans GLocation j’utilisais android.net.http.RequestQueue mais cette API, bien que toujours utilisée en interne par Android, n’est plus publique. Pour la recherche de services j’utilisais une solution un peu complexe faisant appel a Google Search, mais les restrictions de droits d’usage en interdisent plus ou moins l’usage aujourd’hui..

Maps Overlay avec Android SDK 1.5

Apres avoir essayé le nouvel Overlay proposé dans la librairie MyLocationOverlay je l’ai abandonné faute de pouvoir gérer la fréquence de rafraîchissement et donc de pouvoir limiter l’usage du GPS. J’ai ensuite essayé de faire un custom Overlay pour enfin choisir l’ItemizedOverlay qui correspond bien pour gérer les résultats de la recherche.

Description de l’Itemized Overlay

L’ItemizedOverlay est un Overlay qui permet d’ajouter des OverlayItems et ensuite de les sélectionner.

Nous allons d’abord créer une classe Placemark, extension de la class OverlayItem qui définissent les Items contenus dans l’Overlay.

Chaque Object Placemark contiendra les informations de chaque point résultant de la recherche avec des accesseurs pour les extraire si nécessaire.

Cela permettra de récuperer toutes les propriétes venant des résultats des recherches et des les transmettre avec la position, le titre, la description a l’overlay en une fois.

Placemark.java :

package org.example.android.apis;

import android.os.Bundle;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.OverlayItem;
import com.google.map.MapPoint;

/**
* Placemark Object containing
* all informations about our search results
* Definition des parametres :
* http://developer.yahoo.com/search/local/V3/localSearch.html
*
* @author Andre Charles Legendre
*
*/

public class Placemark extends OverlayItem {
String mTitle;
String mSnippet;
GeoPoint mPoint;

private Bundle placeBundle;

public Placemark(GeoPoint point, String title, String snippet,
Bundle placeBundle) {
super(point, title, snippet);
this.placeBundle = placeBundle;
this.mTitle = title;
this.mSnippet = snippet;
this.mPoint = point;
}

public Bundle getBundle() {
return this.placeBundle;
}

public String getid() {
return placeBundle.getString("id");
}

public String getAddress() {
return placeBundle.getString("Address");
}

public String getCity() {
return placeBundle.getString("City");
}

public String getState() {
return placeBundle.getString("State");
}

public String getPhone() {
return placeBundle.getString("Phone");
}

public String getLatitude() {
return placeBundle.getString("Latitude");
}

public String getLongitude() {
return placeBundle.getString("Longitude");
}

public String getRating() {
return placeBundle.getString("Rating");
}

public String getAverageRating() {
return placeBundle.getString("AverageRating");
}

public String getTotalRatings() {
return placeBundle.getString("TotalRatings");
}

public String getTotalReviews() {
return placeBundle.getString("TotalReviews");
}

public String getLastReviewDate() {
return placeBundle.getString("ReviewDate");
}

public String getLastReviewIntro() {
return placeBundle.getString("ReviewIntro");
}

public String getDistance() {
return placeBundle.getString("Distance");
}

public String getUrl() {
return placeBundle.getString("Url");
}

public String getClickUrl() {
return placeBundle.getString("ClickUrl");
}

public String getMapUrl() {
return placeBundle.getString("MapUrl");
}

public String getBusinessUrl() {
return placeBundle.getString("BusinessUrl");
}

public String getBusinessClickUrl() {
return placeBundle.getString("BusinessClickUrl");
}

public Bundle getCategories() {
return placeBundle.getBundle("Categories");
}

public MapPoint getLocation() {
return new MapPoint(Integer.decode(placeBundle.
getString("Latitude")),Integer.decode(placeBundle.
getString("Longitude")));
}

public String toString() {
return (placeBundle.toString());
}
}

Nous allons ensuite créer une classe MapDemoOverlay qui étend ItemizedOverlay.

Les markers des Items sont affichés automatiquement par la classe ItemizedOverlay, pour ce faire on les passe en paramètre à la création de l’Overlay.

La methode clé de cette classe est la methode draw. La methode draw n’a besoin d’afficher que ce qui concerne les titres et autres Toasts ou InfoWindows.

Une des différence majeure concernant la methode draw en 1.5 est l’utilisation de l’objet Projection pour trouver les coordonnées écran à partir des coordonnées geographiques.

La méthode onTap est très simple du fait que onTap de ItemizedOverlay recupère directement l’index de l’item selectionné.

De ce fait en utilisant l’index onTap peut directement récupérer un objet Placemark et ainsi toutes les infos fournis par Yahoo Search.

Place au code pour plus de clarté :

/**
* This method is they key element of our map application
* ...
*/
protected class MapDemoOverlay extends ItemizedOverlay<OverlayItem> {
private List<OverlayItem> items = new ArrayList<OverlayItem>();

public MapDemoOverlay(Drawable marker) {
super(boundCenterBottom(marker));
populate();
}

private Paint innerPaint, borderPaint, textPaint;

@Override
public boolean onTap(int index) {
Placemark placeMark = (Placemark) myLocationOverlay.getItem(index);
Log.e("MapViewDemo", "ONTAP index : " + index + " place : "
+ placeMark.getTitle());
return super.onTap(index);
}

@Override
public void draw(Canvas canvas, MapView myMapView, boolean shadow) {
super.draw(canvas, myMapView, shadow);
// Log.e("MapViewDemo", "MapDemoOverlay...draw");
// Setup our "brush"/"pencil"/ whatever...
Paint paint = new Paint();
paint.setTextSize(12);

// Create a Point that represents our GPS-Location
Double lat = MapViewDemo.this.myLocation.getLatitude() * 1E6;
Double lng = MapViewDemo.this.myLocation.getLongitude() * 1E6;
GeoPoint geoPoint = new GeoPoint(lat.intValue(), lng.intValue());
Projection myprojection = myMapView.getProjection();
Point point = new Point();
myprojection.toPixels(geoPoint, point);
// Setup a color for our location
paint.setStyle(Style.STROKE);
paint.setARGB(255, 80, 150, 30); // Nice strong Android-Green
// Draw our name
canvas.drawText(getString(R.string.map_overlay_own_name),
point.x + 9, point.y, paint);
paint.setStrokeWidth(1);
paint.setARGB(255, 0, 0, 0);
canvas.drawCircle(point.x, point.y, 7, paint);
// Log.e("MapViewDemo", "MapDemoOverlay...draw
paint.setStyle(Style.FILL);
drawInfoWindow(canvas, myprojection, shadow);
ArrayList<Placemark> placeMarks = MapViewDemo.this.getSearch();
Placemark placeMark;
if (placeMarks != null)
synchronized (placeMarks) {
for (int it = 0; it < placeMarks.size(); it++) {
placeMark = (Placemark) placeMarks.get(it);
geoPoint = placeMark.getPoint();
myprojection.toPixels(geoPoint, point);
canvas.drawText(placeMark.getTitle(), point.x + 9,
point.y, paint);
}
}
}

public void addItem(OverlayItem item) {
items.add(item);
populate();
}

@Override
protected OverlayItem createItem(int index) {
return (OverlayItem) items.get(index);
}

@Override
public int size() {
return items.size();
}

private void drawInfoWindow(Canvas canvas, Projection myprojection,
boolean shadow) {

if (MapViewDemo.this.selectedSearchPoint != null) {
GeoPoint geoPoint = MapViewDemo.this.selectedSearchPoint
.getPoint();
Point point = new Point();
myprojection.toPixels(geoPoint, point);

// Setup the info window with the right size & location
int INFO_WINDOW_WIDTH = 150;
int INFO_WINDOW_HEIGHT = 30;
RectF infoWindowRect = new RectF(0, 0, INFO_WINDOW_WIDTH,
INFO_WINDOW_HEIGHT);
int infoWindowOffsetX = point.x - INFO_WINDOW_WIDTH / 2;
int infoWindowOffsetY = point.y - INFO_WINDOW_HEIGHT
- bubbleIcon.getHeight();
infoWindowRect.offset(infoWindowOffsetX, infoWindowOffsetY);

// Draw inner info window
canvas.drawRoundRect(infoWindowRect, 5, 5, getInnerPaint());
// Draw border for info window
canvas.drawRoundRect(infoWindowRect, 5, 5, getBorderPaint());
// Draw the MapLocation's name
int TEXT_OFFSET_X = 10;
int TEXT_OFFSET_Y = 15;
Log.e("Glocation", " selectedSearchPoint5 "
+ MapViewDemo.this.selectedSearchPoint);
canvas.drawText(MapViewDemo.this.selectedSearchPoint
.getSnippet(), infoWindowOffsetX + TEXT_OFFSET_X,
infoWindowOffsetY + TEXT_OFFSET_Y, getTextPaint());
}
}

public Paint getInnerPaint() {
if (innerPaint == null) {
innerPaint = new Paint();
innerPaint.setARGB(225, 75, 75, 75); // gray
innerPaint.setAntiAlias(true);
}
return innerPaint;
}

public Paint getBorderPaint() {
if (borderPaint == null) {
borderPaint = new Paint();
borderPaint.setARGB(255, 255, 255, 255);
borderPaint.setAntiAlias(true);
borderPaint.setStyle(Style.STROKE);
borderPaint.setStrokeWidth(2);
}
return borderPaint;
}

public Paint getTextPaint() {
if (textPaint == null) {
textPaint = new Paint();
textPaint.setARGB(255, 255, 255, 255);
textPaint.setAntiAlias(true);
}
return textPaint;
}
}

Détection des changements de sélection

Lors de la description de la class MapDemoOverlay nous avons présenté la method onTap retournant le numéro de l’item sélectionné.

Cette méthode ne permet pas de détecter facilement les changements de sélection.

Pour le faire nous allons ajouter à notre Overlay un listener ItemizedOverlay.OnFocusChangeListener .

Ce listener est affecté à notre Overlay par l’appel :

myLocationOverlay.setOnFocusChangeListener(FOCUS_LISTENER); où FOCUS_LISTENER est notre OnFocusChangeListener.

Dans notre cas précis le listener tiendra à jour MapViewDemo.this.selectedSearchText utilisé par draw pour afficher le contenu de infoWindow donnant des informations au sujet de l’item sélectionné par l’utilisateur.

ItemizedOverlay.OnFocusChangeListener FOCUS_LISTENER = new ItemizedOverlay.OnFocusChangeListener() {
public void onFocusChanged(ItemizedOverlay overlay, OverlayItem newFocus) {
if (newFocus != null) {
Log.e("MapViewDemo", "MapViewDemo ChangeFocus "
+ newFocus.getTitle());
}
MapViewDemo.this.selectedSearchPoint = (Placemark) newFocus;
}
};
}

Description de la gestion de la géolocalisation

En utilisant la géolocalisation nous pouvons obtenir notre position immédiate.

Nous pouvons aussi créer un LocationListener en charge de gérer nos changements de position.

Pour simplifier le code nous avons groupé cela dans une méthode initMyLocation() appellée au démarrage, dans la méthode onCreate.

initMyLocation affiche d’abord notre position courante en appelant myLocationManager.getLastKnownLocation et initialise le rafraîchissement de notre position quand on se deplace en créant un LocationListener et en le passant en paramètre a this.myLocationManager.requestLocationUpdates.

Cette solution nous permet de configurer la fréquence des mises à jour de notre position à l’aide des 2 paramètres :

MINIMUM_TIME_BETWEEN_UPDATE, MINIMUM_DISTANCECHANGE_FOR_UPDATE

initMyLocation initialise aussi l’overlay dans lequel seront affichés notre geolocalisation et les résultats de nos recherches :

/**
* Initialises the MyLocationOverlay and adds it to the overlays of the map
* Prepare the things, that will give us the ability, to receive
* Information about our GPS-Position.
*/
private void initMyLocation() {
myLocationOverlay = new MapDemoOverlay(marker);
myLocationOverlay.setOnFocusChangeListener(FOCUS_LISTENER);
myMapView.getOverlays().add(myLocationOverlay);
this.myLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
this.myLocation = myLocationManager.getLastKnownLocation("gps");
Double lat = this.myLocation.getLatitude() * 1E6;
Double lng = this.myLocation.getLongitude() * 1E6;
GeoPoint geoPoint = new GeoPoint(lat.intValue(), lng.intValue());
this.myMapController.setCenter(geoPoint);
this.myMapController.setZoom(11);
myMapView.setClickable(true);
myMapView.setEnabled(true);
/*
* Register with out LocationManager to send us an intent (whos
* Action-String we defined above) when an intent to the location
* manager, that we want to get informed on changes to our own position.
*/
locListener = new LocationListener() {

public void onLocationChanged(Location newLocation) {
if (System.currentTimeMillis() > MapViewDemo.this.endTime) {
MapViewDemo.this.endTime = System.currentTimeMillis()
+ MINIMUM_TIME_BETWEEN_UPDATE_LIST;
}
if (MapViewDemo.this.doUpdates)
MapViewDemo.this.updateView(newLocation);
}

public void onProviderDisabled(String provider) {
}

public void onProviderEnabled(String provider) {
}

Utilisation de HttpClient pour appeler Yahoo Search

La version du code est une version simpliste où l’application attend la réponse et son formattage.

Une version utilisable en production supposerait de créer un thread pour gérer ces traitements en background.

J’ai préféré simplifier pour garder la lisibilité.

Android propose deux libraries pour les connection http (3 si on compte les sockets).

La premiere est android.net et la second org.apache.http.client.HttpClient .

J’utilise cette dernière car j’ai déjà eu a l’utiliser par ailleurs et que c’est un outil très stable et  efficace.

Pour faciliter la réutilisation de ce code j’ai créé un objet MapDemoConnection en charge de gérer la connection http avec le service Yahoo Search.

Cet objet construit l’addresse url, l’appelle, recupère les données et lance le parsing.

MapDemoConnection.java :

package org.example.android.apis;import java.io.IOException;

import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.xml.sax.SAXException;

import android.util.Log;
import android.util.Xml;

/**
* MapDemoConnection sends http requests to the web service.
*
* @author Andre Charles Legendre
*
*/

public class MapDemoConnection {

private static String USER_AGENT = "Mozilla/4.5";
private static String TAG = "MapDemoConnection";

private String password;
private String serverUrl;

public MapDemoConnection(String serverUrl, String username, String password) {
this.serverUrl = serverUrl;
this.password = password;
}

/**
* Call Service and parse results
*
* @param resource
*            String containing text you want to search with
* @param resourceType
*            String GET or POST
* @param httpParams
*            List<NameValuePair> List of parameters send to the service
* @param myContentHandler
*            MyContentHandler Object in charge to parse the result
* @return ArrayList<Placemark> containing List of PlaceMark one for each
*         result of the search
*/

public ArrayList<Placemark> parse(String resource, String resourceType,
List<NameValuePair> httpParams, MyContentHandler myContentHandler) {
if (resource.length() > 140) {
throw new IllegalArgumentException(
"Search text is longer than 140 characters");
}
String xml = null;
try {
if (resourceType.equals("GET")) {
xml = getRequest(resource);
} else {
xml = postRequest(resource,
new UrlEncodedFormEntity(httpParams));
}
} catch (SocketTimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (xml != null) {
try {
Log.e("MyEventHandler", "xml=" + xml);
Xml.parse(xml, myContentHandler);
} catch (SAXException e) {
Log.e("MyEventHandler", "xml=" + xml + "ERROR=" + e.toString());
}
return myContentHandler.parse();
}
return null;
}

/**
* Sends a GET request to web service
*
* @param resource
* @return String response from the server
*/
private String getRequest(String resource) {
String result = null;
String url = serverUrl + resource;
Log.d(TAG, "GET: " + url);

HttpClient client = new DefaultHttpClient(new BasicHttpParams());
HttpGet getMethod = new HttpGet((url));
try {
getMethod.setHeader("User-Agent", USER_AGENT);
getMethod.addHeader("Authorization", "Basic " + getCredentials());

HttpResponse httpResponse = client.execute(getMethod);
result = retrieveInputStream(httpResponse.getEntity());

} catch (Exception e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
} finally {
getMethod.abort();
}
Log.e(TAG, result);
return result;
}

/**
* Sends a POST request
*
* @param resource
* @param formParams
*            UrlEncodedFormEntity which is comprised of a List of
*            NameValuePairs
* @return String response from the server
* @throws SocketTimeoutException
*             , SocketException
*/
private String postRequest(String resource, UrlEncodedFormEntity formParams)
throws SocketTimeoutException, SocketException {
String result = null;
String url = serverUrl + resource;
Log.d(TAG, "POST: " + url);

HttpClient client = new DefaultHttpClient(new BasicHttpParams());
HttpPost postMethod = new HttpPost((url));
try {
// postMethod.setHeader("User-Agent", USER_AGENT);
// postMethod.addHeader("Authorization", "Basic " +
// getCredentials());

if (formParams != null)
postMethod.setEntity(formParams);

HttpResponse httpResponse = client.execute(postMethod);
result = EntityUtils.toString(httpResponse.getEntity());

if (result != null)
Log.d(TAG, "Returned response [" + httpResponse.getStatusLine()
+ "] from the server: " + result);

} catch (Exception e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
} finally {
postMethod.abort();
}
return result;
}

/**
* Retrieves the content input stream from a GET request
*
* @param httpEntity
* @return String service response
*/
private String retrieveInputStream(final HttpEntity httpEntity) {
int length = (int) httpEntity.getContentLength();
StringBuffer stringBuffer = new StringBuffer(length);
try {
InputStreamReader inputStreamReader = new InputStreamReader(
httpEntity.getContent(), HTTP.UTF_8);
char buffer[] = new char[length];
int count;

while ((count = inputStreamReader.read(buffer, 0, length - 1)) > 0) {
stringBuffer.append(buffer, 0, count);
}
} catch (UnsupportedEncodingException e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
} catch (IllegalStateException e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
}
return stringBuffer.toString();
}

/**
* Retrieves the credentials
*
* @return String password
*/
private String getCredentials() {
return password;
// return new String(Base64.encode((username + ":" +
// password).getBytes()));
}
}

Parsing des données reçues de Yahoo Search

searchmaps

Pour le parsing nous allons créer un object MyContentHandler en charge de mettre en forme les données reçues.

Ces données reçues seront mises dans un ArrayList d’objects PlaceMark.

La fonction draw de l’ItemizedOveraly sera en charge d’afficher ces PlaceMark et de gérer leur interactivité.

Nous utilisons le package de org.xml.sax pour le parsing.

MyContentHandler extends DefaultHandler et doit donc implémenter toutes les méthodes startElement, endElement, etc.

En fait MapDemoConnection lance le parsing en appelant Xml.parse(xml, myContentHandler) où le paramètre xml contient les données reçues et où myContentHandler est l’objet en charge de les parser.

Lors du parsing myContentHandler appelle les méthodes startElement, endElement, etc. quand il reçoit une notification à chaque étape de la lecture du document.

MyContentHandler

package org.example.android.apis;import java.util.ArrayList;

import java.util.Iterator;
import java.util.Set;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.google.android.maps.GeoPoint;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

/**
* MapViewDemo is the Map Activity of our application
*
* @author Andre Charles Legendre
*
*/

public class MyContentHandler extends DefaultHandler {
StringBuilder elementBuilder = null;
private String id;
private int numCat;
private Bundle bundle;
private Bundle categories;
private Bundle bundles;
private String title;
private String snippet;

public MyContentHandler(Activity activity) {
}

public ArrayList<Placemark> parse() {
return getPlaceMarks(this.bundles);
}

@Override
public void startDocument() throws SAXException {
// Log.e("MapDemoMYCONTENTHANDLER", "STARTDOCUMENT");
this.bundles = new Bundle();
}

public void endDocument() throws SAXException {
Log.e("MapDemoMYCONTENTHANDLER", "Finish");
}

@Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
// Log.e("MapDemoMYCONTENTHANDLER", "STARTELEMENT " + localName);
elementBuilder = new StringBuilder();
if (localName.equals("Categories")) {
this.numCat = 0;
categories = new Bundle();
} else if (localName.equals("Result")) {
id = atts.getValue("id");
bundle = new Bundle();
}
}

@Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
String text = elementBuilder.toString();
//Log.e("MapDemoMYCONTENTHANDLER", "ENDELEMENT " + localName + " : "
//            + text);
if (localName.equals("ResultSetMapUrl")) {
} else if (localName.equals("Result")) {
bundles.putBundle(id, bundle);
} else if (localName.equals("Categories")) {
bundle.putBundle(id, categories);
} else if (localName.equals("Category")) {
categories.putString("" + numCat, text);
} else {
bundle.putString(localName, text);
}
}

@Override
public void characters(char[] chars, int i, int i1) throws SAXException {
if (elementBuilder == null) {
Log.e("MapDemoMYCONTENTHANDLER", "elementBuilder NULL");
elementBuilder = new StringBuilder();
}
elementBuilder.append(chars, i, i1);
}

/**
* Parse results
*
* @param mSearch
*            Bundle containing results data
* @return ArrayList<Placemark> containing List of PlaceMark one for each
*         result of the search
* @throws IOException
*/

private ArrayList<Placemark> getPlaceMarks(Bundle mSearch) {
ArrayList<Placemark> placeMarks = new ArrayList<Placemark>();
if (mSearch != null)
synchronized (mSearch) {
Bundle placeBundles = mSearch;
Set<String> places = placeBundles.keySet();
Placemark placeMark = null;
Bundle Categories;
String Latitude = "0.0000";
String Longitude = "0.0000";
Double lat;
Double lng;
GeoPoint geoPoint;
String fieldName;
Bundle placeBundle;
Set<String> placeFields;
Set<String> categories;

for (Iterator<String> it = places.iterator(); it.hasNext();) {
placeBundle = placeBundles.getBundle(it.next());
placeFields = placeBundle.keySet();
for (Iterator<String> iter = placeFields.iterator(); iter
.hasNext();) {
fieldName = iter.next();
if (fieldName.equals("Categories")) {
Categories = placeBundle.getBundle(fieldName);
categories = Categories.keySet();
for (Iterator<String> itr = categories.iterator(); itr
.hasNext();) {
// TODO utiliser les categories
@SuppressWarnings("unused")
String catName = Categories.getString(itr
.next());
}
} else if (fieldName.equals("Latitude")) {
Latitude = placeBundle.getString(fieldName);
} else if (fieldName.equals("Longitude")) {
Longitude = placeBundle.getString(fieldName);
} else if (fieldName.equals("Title")) {
title = placeBundle.getString(fieldName);
} else if (fieldName.equals("LastReviewIntro")) {
snippet = placeBundle.getString(fieldName);
}
}
// Placemark placemark = search.getPlacemark(i);
// Log.e("GlocationMAP", "MyLocationOverlay...draw
// Search " + i);
Log.e("GlocationMAP", "MyLocationOverlay...snippet "
+ snippet);
lat = Double.valueOf(Latitude) * 1E6;
lng = Double.valueOf(Longitude) * 1E6;
geoPoint = new GeoPoint(lat.intValue(), lng.intValue());
placeMark = new Placemark(geoPoint, title, snippet,
placeBundle);
// placeMark.setMarker(marker);
placeMarks.add(placeMark);
}
}
return placeMarks;
}
}

Ecran de saisie de la requête utilisateur de recherche

Nous allons créer une nouvelle activité SearchActivity pour permettre à l’utilisateur de saisir une recherche.

SearchActivity doit créer un espace de saise du texte et un bouton pour lancer la recherche.

La syntaxe des recherches que l’utilisateur doir entrer est celle de Yahoo Search.

Votre location doit être a l’intérieur des Etats-Unis du à la limitation de Yahoo Search, autrement vous n’aurez aucun résultat.

On limite la longueur a 140 caractères.

SearchActivity.java

package org.example.android.apis;import android.app.Activity;

import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.view.View;

/**
* SearchActivity Activity getting search from user sending result by an intent
*
* @author Andre Charles Legendre
*
*/

public class SearchActivity extends Activity {
protected static final String ACTIVITY_RESULT = "org.example.android.apis.EDIT";

public SearchActivity() {
}

/**
* Called with the activity is first created.
*/
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);

// Set the layout for this activity.
setContentView(R.layout.search);

Button addButton = (Button) findViewById(R.id.searchButton);
addButton.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {
Intent i = new Intent();
// We limit length to 140 to avoid exception in
// MapDemoConnection
String result = ((EditText) findViewById(R.id.searchText)).getText().toString();
if (result.length() > 140)
result = result.substring(0, 139);
i.putExtra(ACTIVITY_RESULT,result);
setResult(RESULT_OK, i);
finish();
}
});

}
}

On doit bien entendu déclarer cette Activity dans le fichier AndroidManifest.xml pour pouvoir l’utiliser.

Nous avons par ailleurs ajouté dans MapViewDemo.java une option au menu et un KeyEvent pour KEY_F pour lancer SearchActivity :

<?xml version=“1.0” encoding=“utf-8”?>
<manifest xmlns:android=“http://schemas.android.com/apk/res/android” package=“org.example.android.apis”>
<permission xmlns:android=“http://schemas.android.com/apk/res/android” android:name=“android.permission.INTERNET”></permission>
<uses-permission android:name=“android.permission.INTERNET” />
<uses-permission android:name=“android.permission.ACCESS_FINE_LOCATION” />
<application android:label=“@string/app_name”
android:icon=“@drawable/icon” android:name=“MapDemoApplication”>
<uses-library android:name=“com.google.android.maps” />
<activity android:name=“.MapViewDemo” android:label=“@string/app_name”>
<intent-filter>
<action android:name=“android.intent.action.MAIN” />
<category android:name=“android.intent.category.DEFAULT” />
<category android:name=“android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
<activity android:name=“.SearchActivity” android:label=“Find”>
<intent-filter>
<action android:name=“android.intent.action.MAIN”/>
<category android:name=“android.intent.category.GLOCATION”/>
<action android:name=“android.intent.action.SEARCH” />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion=“3” />
</manifest>

Conclusion

Nous voilà au bout de ce tutorials qui nous a permis de voir beaucoup de nouveaux éléments.

Il y en aura encore dans la suite, nous verrons ce que ça donne avec Google Search.

Nous aborderons également le composant WebView et les interactions possible avec Java et  JavaScript. Attention ça va en surprendre plus d’un…

J’attends vos remarques, critiques, propositions d’amelioration.

Télécharger les sources

Related Articles

Comment activer ou désactiver les “Sons Système” sur un dispositif Android

Faly

Tutoriel Android : "Hello World" version 1.5

L'orfèvre

installer une application du Google play

sylvain

54 comments

Leave a Comment