In this article, we will develop an Android application which displays nearby places as a set of markers in Google Maps Android API V2 corresponding to the user touched location in the Google Maps and place type selected in the Spinner view.
On clicking a marker, the place details like place name, vicinity and photo ( if available ) will be shown in dialog fragment window.
Screenshots of the application is available towards the end of this article.
Some of the user defined classes that are used in this application are explained below :
MainActivity : This is the activity class which is opened when the application launches.
PlaceDialogFragment : A dialog window which is opened on clicking a marker. It shows place name, vicinity and photo corresponding to the marked place.
PlacesTask : This is an inner class of the MainActivity class and is extending the class AsycTask. PlacesTask is used to fetch JSON data from Google Places Web Service in non-ui thread.
ParserTask : This is an inner class of the MainActivity class and is extending the class AsyncTask. ParserTask is used to parse the JSON data fetched from Google Places Web Service in a non-ui thread.
ImageDownloadTask : This is an inner class of PlaceDialogFragment and is extending the class AsyncTask. This is used to download image from Google Places Web Service.
Place : This class represents a nearby location with the information like latitude, longitude, place name, vicinity and photos. We are making this as a Parcelable class in order to retain the instances of this class during screen rotation.
Photo : This class represents a photo returned from Google Places Web Service with the information like width, height, photo reference and attributions. This is also a parcelable class.
Attribution : This class is used to represent photo attributions. This is also a parcelable class.
PlaceJSONParser : A utility class to parse JSON data.
This application is developed in Eclipse (4.2.1) with ADT plugin (21.1.0) and Android SDK (21.1.0) and tested in Android devices with versions 2.3.6 ( Gingerbread ) and 4.0.4 ( Ice Cream Sandwich ).
1. Create a new Android application project namely “LocationNearbyPlacesPhotos”
2. Configure the project
3. Design application launcher icon
4. Create a blank activity
5. Enter MainActivity details
6. Download and configure Google Play Services Library in Eclipse
Please follow the given below link to setup Google Play Service library in Eclipse.
http://developer.android.com/google/play-services/setup.html
7. Add Google Play Services Library to this project
8. Get the API key for Google Maps Android API V2
We need to get an API key from Google to use Google Maps in Android application.
Please follow the given below link to get the API key for Google Maps Android API v2.
https://developers.google.com/maps/documentation/android/start
9. Get the API key for Google Places API
We can create API key for Google Place API by clicking “Create new Browser key” available at the “API Access” pane of the Google console URL : http://code.google.com/apis/console.
Also ensure that, “Places API” is enabled in the “Services” pane of the Google console.
10. Add Android Support library to this project
By default, Android support library (android-support-v4.jar ) is added to this project by Eclipse IDE to the directory libs. If it is not added, we can do it manually by doing the following steps :
- Open Project Explorer by Clicking “Window -> Show View -> Project Explorer”
- Right click this project
- Then from popup menu, Click “Android Tools -> Add Support Library “
11. Update the file res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">LocationNearby</string> <string name="hello_world">Hello world!</string> <string name="menu_settings">Settings</string> <string name="str_btn_find">Find</string> <string-array name="place_type"> <item>airport</item> <item>atm</item> <item>bank</item> <item>bus_station</item> <item>church</item> <item>doctor</item> <item>hospital</item> <item>mosque</item> <item>movie_theater</item> <item>hindu_temple</item> <item>restaurant</item> </string-array> <string-array name="place_type_name"> <item>Airport</item> <item>ATM</item> <item>Bank</item> <item>Bus Station</item> <item>Church</item> <item>Doctor</item> <item>Hospital</item> <item>Mosque</item> <item>Movie Theater</item> <item>Hindu Temple</item> <item>Restaurant</item> </string-array> </resources>
Note : Defining string arrays to populate Spinner Widget with Place types.
12. Update the layout file res/layout/activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <Spinner android:id="@+id/spr_place_type" android:layout_width="wrap_content" android:layout_height="60dp" android:layout_alignParentTop="true" /> <Button android:id="@+id/btn_find" android:layout_width="wrap_content" android:layout_height="60dp" android:layout_alignParentTop="true" android:layout_toRightOf="@id/spr_place_type" android:text="@string/str_btn_find" /> <fragment android:id="@+id/map" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/spr_place_type" class="com.google.android.gms.maps.SupportMapFragment" /> </RelativeLayout>
13. Create the layout file res/layout/dialog_layout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" andoid:layout_height="wrap_content" android:orientation="vertical" android:gravity="center_horizontal" > <TextView android:id="@+id/tv_vicinity" android:layout_width="wrap_content" android:layout_height="wrap_content" android:maxLines="2" /> <ViewFlipper android:id="@+id/flipper" android:layout_width="wrap_content" android:layout_height="wrap_content" > </ViewFlipper> <TextView android:id="@+id/tv_photos_count" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
14. Create the class “Attribution” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/Attribution.java
package in.wptrafficanalyzer.locationnearbyplacesphotos; import android.os.Parcel; import android.os.Parcelable; public class Attribution implements Parcelable{ // Attribution of the photo String mHtmlAttribution=""; @Override public int describeContents() { return 0; } /** Writing Attribution object data to Parcel */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mHtmlAttribution); } public Attribution(){ } /** Initializing Attribution object from Parcel object */ private Attribution(Parcel in){ this.mHtmlAttribution = in.readString(); } /** Generates an instance of Attribution class from Parcel */ public static final Parcelable.Creator<Attribution> CREATOR = new Parcelable.Creator<Attribution>() { @Override public Attribution createFromParcel(Parcel source) { return new Attribution(source); } @Override public Attribution[] newArray(int size) { // TODO Auto-generated method stub return null; } }; }
15. Create the class “Photo” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/Photo.java
package in.wptrafficanalyzer.locationnearbyplacesphotos; import android.os.Parcel; import android.os.Parcelable; public class Photo implements Parcelable{ // Width of the Photo int mWidth=0; // Height of the Photo int mHeight=0; // Reference of the photo to be used in Google Web Services String mPhotoReference=""; // Attributions of the photo // Attribution is a Parcelable class Attribution[] mAttributions={}; @Override public int describeContents() { // TODO Auto-generated method stub return 0; } /** Writing Photo object data to Parcel */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mWidth); dest.writeInt(mHeight); dest.writeString(mPhotoReference); dest.writeParcelableArray(mAttributions, 0); } public Photo(){ } /** Initializing Photo object from Parcel object */ private Photo(Parcel in){ this.mWidth = in.readInt(); this.mHeight = in.readInt(); this.mPhotoReference = in.readString(); this.mAttributions = (Attribution[])in.readParcelableArray(Attribution.class.getClassLoader()); } /** Generates an instance of Place class from Parcel */ public static final Parcelable.Creator<Photo> CREATOR = new Parcelable.Creator<Photo>() { @Override public Photo createFromParcel(Parcel source) { return new Photo(source); } @Override public Photo[] newArray(int size) { // TODO Auto-generated method stub return null; } }; }
16. Create the class “Place” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/Place.java
package in.wptrafficanalyzer.locationnearbyplacesphotos; import android.os.Parcel; import android.os.Parcelable; public class Place implements Parcelable{ // Latitude of the place String mLat=""; // Longitude of the place String mLng=""; // Place Name String mPlaceName=""; // Vicinity of the place String mVicinity=""; // Photos of the place // Photo is a Parcelable class Photo[] mPhotos={}; @Override public int describeContents() { // TODO Auto-generated method stub return 0; } /** Writing Place object data to Parcel */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mLat); dest.writeString(mLng); dest.writeString(mPlaceName); dest.writeString(mVicinity); dest.writeParcelableArray(mPhotos, 0); } public Place(){ } /** Initializing Place object from Parcel object */ private Place(Parcel in){ this.mLat = in.readString(); this.mLng = in.readString(); this.mPlaceName = in.readString(); this.mVicinity = in.readString(); this.mPhotos = (Photo[])in.readParcelableArray(Photo.class.getClassLoader()); } /** Generates an instance of Place class from Parcel */ public static final Parcelable.Creator<Place> CREATOR = new Parcelable.Creator<Place>(){ @Override public Place createFromParcel(Parcel source) { return new Place(source); } @Override public Place[] newArray(int size) { // TODO Auto-generated method stub return null; } }; }
17. Create the class “PlaceJSONParser” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/PlaceJSONParser.java
package in.wptrafficanalyzer.locationnearbyplacesphotos; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.util.Log; public class PlaceJSONParser { /** Receives a JSONObject and returns a list */ public Place[] parse(JSONObject jObject){ JSONArray jPlaces = null; try { /** Retrieves all the elements in the 'places' array */ jPlaces = jObject.getJSONArray("results"); } catch (JSONException e) { e.printStackTrace(); } /** Invoking getPlaces with the array of json object * where each json object represent a place */ return getPlaces(jPlaces); } private Place[] getPlaces(JSONArray jPlaces){ int placesCount = jPlaces.length(); Place[] places = new Place[placesCount]; /** Taking each place, parses and adds to list object */ for(int i=0; i<placesCount;i++){ try { /** Call getPlace with place JSON object to parse the place */ places[i] = getPlace((JSONObject)jPlaces.get(i)); } catch (JSONException e) { e.printStackTrace(); } } return places; } /** Parsing the Place JSON object */ private Place getPlace(JSONObject jPlace){ Place place = new Place(); try { // Extracting Place name, if available if(!jPlace.isNull("name")){ place.mPlaceName = jPlace.getString("name"); } // Extracting Place Vicinity, if available if(!jPlace.isNull("vicinity")){ place.mVicinity = jPlace.getString("vicinity"); } if(!jPlace.isNull("photos")){ JSONArray photos = jPlace.getJSONArray("photos"); place.mPhotos = new Photo[photos.length()]; for(int i=0;i<photos.length();i++){ place.mPhotos[i] = new Photo(); place.mPhotos[i].mWidth = ((JSONObject)photos.get(i)).getInt("width"); place.mPhotos[i].mHeight = ((JSONObject)photos.get(i)).getInt("height"); place.mPhotos[i].mPhotoReference = ((JSONObject)photos.get(i)).getString("photo_reference"); JSONArray attributions = ((JSONObject)photos.get(i)).getJSONArray("html_attributions"); place.mPhotos[i].mAttributions = new Attribution[attributions.length()]; for(int j=0;j<attributions.length();j++){ place.mPhotos[i].mAttributions[j] = new Attribution(); place.mPhotos[i].mAttributions[j].mHtmlAttribution = attributions.getString(j); } } } place.mLat = jPlace.getJSONObject("geometry").getJSONObject("location").getString("lat"); place.mLng = jPlace.getJSONObject("geometry").getJSONObject("location").getString("lng"); } catch (JSONException e) { e.printStackTrace(); Log.d("EXCEPTION", e.toString()); } return place; } }
18. Create the class “PlaceDialogFragment” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/PlaceDialogFragment.java
package in.wptrafficanalyzer.locationnearbyplacesphotos; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import android.widget.ViewFlipper; // Defining DialogFragment class to show the place details with photo public class PlaceDialogFragment extends DialogFragment{ TextView mTVPhotosCount = null; TextView mTVVicinity = null; ViewFlipper mFlipper = null; Place mPlace = null; DisplayMetrics mMetrics = null; public PlaceDialogFragment(){ super(); } public PlaceDialogFragment(Place place, DisplayMetrics dm){ super(); this.mPlace = place; this.mMetrics = dm; } @Override public void onCreate(Bundle savedInstanceState) { // For retaining the fragment on screen rotation setRetainInstance(true); super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.dialog_layout, null); // Getting reference to ViewFlipper mFlipper = (ViewFlipper) v.findViewById(R.id.flipper); // Getting reference to TextView to display photo count mTVPhotosCount = (TextView) v.findViewById(R.id.tv_photos_count); // Getting reference to TextView to display place vicinity mTVVicinity = (TextView) v.findViewById(R.id.tv_vicinity); if(mPlace!=null){ // Setting the title for the Dialog Fragment getDialog().setTitle(mPlace.mPlaceName); // Array of references of the photos Photo[] photos = mPlace.mPhotos; // Setting Photos count mTVPhotosCount.setText("Photos available : " + photos.length); // Setting the vicinity of the place mTVVicinity.setText(mPlace.mVicinity); // Creating an array of ImageDownloadTask to download photos ImageDownloadTask[] imageDownloadTask = new ImageDownloadTask[photos.length]; int width = (int)(mMetrics.widthPixels*3)/4; int height = (int)(mMetrics.heightPixels*1)/2; String url = "https://maps.googleapis.com/maps/api/place/photo?"; String key = "key=YOUR_BROWSER_KEY"; String sensor = "sensor=true"; String maxWidth="maxwidth=" + width; String maxHeight = "maxheight=" + height; url = url + "&" + key + "&" + sensor + "&" + maxWidth + "&" + maxHeight; // Traversing through all the photoreferences for(int i=0;i<photos.length;i++){ // Creating a task to download i-th photo imageDownloadTask[i] = new ImageDownloadTask(); String photoReference = "photoreference="+photos[i].mPhotoReference; // URL for downloading the photo from Google Services url = url + "&" + photoReference; // Downloading i-th photo from the above url imageDownloadTask[i].execute(url); } } return v; } @Override public void onDestroyView() { if (getDialog() != null && getRetainInstance()) getDialog().setDismissMessage(null); super.onDestroyView(); } private Bitmap downloadImage(String strUrl) throws IOException{ Bitmap bitmap=null; InputStream iStream = null; try{ URL url = new URL(strUrl); /** Creating an http connection to communcate with url */ HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); /** Connecting to url */ urlConnection.connect(); /** Reading data from url */ iStream = urlConnection.getInputStream(); /** Creating a bitmap from the stream returned from the url */ bitmap = BitmapFactory.decodeStream(iStream); }catch(Exception e){ Log.d("Exception while downloading url", e.toString()); }finally{ iStream.close(); } return bitmap; } private class ImageDownloadTask extends AsyncTask<String, Integer, Bitmap>{ Bitmap bitmap = null; @Override protected Bitmap doInBackground(String... url) { try{ // Starting image download bitmap = downloadImage(url[0]); }catch(Exception e){ Log.d("Background Task",e.toString()); } return bitmap; } @Override protected void onPostExecute(Bitmap result) { // Creating an instance of ImageView to display the downloaded image ImageView iView = new ImageView(getActivity().getBaseContext()); // Setting the downloaded image in ImageView iView.setImageBitmap(result); // Adding the ImageView to ViewFlipper mFlipper.addView(iView); // Showing download completion message Toast.makeText(getActivity().getBaseContext(), "Image downloaded successfully", Toast.LENGTH_SHORT).show(); } } }
Note : Ensure that “YOUR_BROWSER_KEY” at the line 84 is replaced with the api key obtained in Step 9
19. Update the class “MainActivity” in the file src/in/wptrafficanalyzer/locationnearbyplacesphotos/MainActivity.java
import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import org.json.JSONObject; import android.app.Dialog; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.util.DisplayMetrics; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.Spinner; import android.widget.Toast; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMap.OnMapClickListener; import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; public class MainActivity extends FragmentActivity{ // GoogleMap GoogleMap mGoogleMap; // Spinner in which the location types are stored Spinner mSprPlaceType; // A button to find the near by places Button mBtnFind=null; // Stores near by places Place[] mPlaces = null; // A String array containing place types sent to Google Place service String[] mPlaceType=null; // A String array containing place types displayed to user String[] mPlaceTypeName=null; // The location at which user touches the Google Map LatLng mLocation=null; // Links marker id and place object HashMap<String, Place> mHMReference = new HashMap<String, Place>(); // Specifies the drawMarker() to draw the marker with default color private static final float UNDEFINED_COLOR = -1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Array of place types mPlaceType = getResources().getStringArray(R.array.place_type); // Array of place type names mPlaceTypeName = getResources().getStringArray(R.array.place_type_name); // Creating an array adapter with an array of Place types // to populate the spinner ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, mPlaceTypeName); // Getting reference to the Spinner mSprPlaceType = (Spinner) findViewById(R.id.spr_place_type); // Setting adapter on Spinner to set place types mSprPlaceType.setAdapter(adapter); // Getting reference to Find Button mBtnFind = ( Button ) findViewById(R.id.btn_find); // Getting Google Play availability status int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext()); if(status!=ConnectionResult.SUCCESS){ // Google Play Services are not available int requestCode = 10; Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this, requestCode); dialog.show(); }else { // Google Play Services are available // Getting reference to the SupportMapFragment SupportMapFragment fragment = ( SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); // Getting Google Map mGoogleMap = fragment.getMap(); // Enabling MyLocation in Google Map mGoogleMap.setMyLocationEnabled(true); // Handling screen rotation if(savedInstanceState !=null) { // Removes all the existing links from marker id to place object mHMReference.clear(); //If near by places are already saved if(savedInstanceState.containsKey("places")){ // Retrieving the array of place objects mPlaces = (Place[]) savedInstanceState.getParcelableArray("places"); // Traversing through each near by place object for(int i=0;i<mPlaces.length;i++){ // Getting latitude and longitude of the i-th place LatLng point = new LatLng(Double.parseDouble(mPlaces[i].mLat), Double.parseDouble(mPlaces[i].mLng)); // Drawing the marker corresponding to the i-th place Marker m = drawMarker(point,UNDEFINED_COLOR); // Linkng i-th place and its marker id mHMReference.put(m.getId(), mPlaces[i]); } } // If a touched location is already saved if(savedInstanceState.containsKey("location")){ // Retrieving the touched location and setting in member variable mLocation = (LatLng) savedInstanceState.getParcelable("location"); // Drawing a marker at the touched location drawMarker(mLocation, BitmapDescriptorFactory.HUE_GREEN); } } // Setting click event lister for the find button mBtnFind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int selectedPosition = mSprPlaceType.getSelectedItemPosition(); String type = mPlaceType[selectedPosition]; mGoogleMap.clear(); if(mLocation==null){ Toast.makeText(getBaseContext(), "Please mark a location", Toast.LENGTH_SHORT).show(); return; } drawMarker(mLocation, BitmapDescriptorFactory.HUE_GREEN); StringBuilder sb = new StringBuilder("https://maps.googleapis.com/maps/api/place/nearbysearch/json?"); sb.append("location="+mLocation.latitude+","+mLocation.longitude); sb.append("&radius=5000"); sb.append("&types="+type); sb.append("&sensor=true"); sb.append("&key=YOUR_BROWSER_KEY"); // Creating a new non-ui thread task to download Google place json data PlacesTask placesTask = new PlacesTask(); // Invokes the "doInBackground()" method of the class PlaceTask placesTask.execute(sb.toString()); } }); // Map Click listener mGoogleMap.setOnMapClickListener(new OnMapClickListener() { @Override public void onMapClick(LatLng point) { // Clears all the existing markers mGoogleMap.clear(); // Setting the touched location in member variable mLocation = point; // Drawing a marker at the touched location drawMarker(mLocation,BitmapDescriptorFactory.HUE_GREEN); } }); // Marker click listener mGoogleMap.setOnMarkerClickListener(new OnMarkerClickListener() { @Override public boolean onMarkerClick(Marker marker) { // If touched at User input location if(!mHMReference.containsKey(marker.getId())) return false; // Getting place object corresponding to the currently clicked Marker Place place = mHMReference.get(marker.getId()); // Creating an instance of DisplayMetrics DisplayMetrics dm = new DisplayMetrics(); // Getting the screen display metrics getWindowManager().getDefaultDisplay().getMetrics(dm); // Creating a dialog fragment to display the photo PlaceDialogFragment dialogFragment = new PlaceDialogFragment(place,dm); // Getting a reference to Fragment Manager FragmentManager fm = getSupportFragmentManager(); // Starting Fragment Transaction FragmentTransaction ft = fm.beginTransaction(); // Adding the dialog fragment to the transaction ft.add(dialogFragment, "TAG"); // Committing the fragment transaction ft.commit(); return false; } }); } } /** * A callback function, executed on screen rotation */ @Override protected void onSaveInstanceState(Bundle outState) { // Saving all the near by places objects if(mPlaces!=null) outState.putParcelableArray("places", mPlaces); // Saving the touched location if(mLocation!=null) outState.putParcelable("location", mLocation); super.onSaveInstanceState(outState); } /** A method to download json data from argument url */ private String downloadUrl(String strUrl) throws IOException{ String data = ""; InputStream iStream = null; HttpURLConnection urlConnection = null; try{ URL url = new URL(strUrl); // Creating an http connection to communicate with url urlConnection = (HttpURLConnection) url.openConnection(); // Connecting to url urlConnection.connect(); // Reading data from url iStream = urlConnection.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(iStream)); StringBuffer sb = new StringBuffer(); String line = ""; while( ( line = br.readLine()) != null){ sb.append(line); } data = sb.toString(); br.close(); }catch(Exception e){ Log.d("Exception while downloading url", e.toString()); }finally{ iStream.close(); urlConnection.disconnect(); } return data; } /** A class, to download Google Places */ private class PlacesTask extends AsyncTask<String, Integer, String>{ String data = null; // Invoked by execute() method of this object @Override protected String doInBackground(String... url) { try{ data = downloadUrl(url[0]); }catch(Exception e){ Log.d("Background Task",e.toString()); } return data; } // Executed after the complete execution of doInBackground() method @Override protected void onPostExecute(String result){ ParserTask parserTask = new ParserTask(); // Start parsing the Google places in JSON format // Invokes the "doInBackground()" method of ParserTask parserTask.execute(result); } } /** A class to parse the Google Places in JSON format */ private class ParserTask extends AsyncTask<String, Integer, Place[]>{ JSONObject jObject; // Invoked by execute() method of this object @Override protected Place[] doInBackground(String... jsonData) { Place[] places = null; PlaceJSONParser placeJsonParser = new PlaceJSONParser(); try{ jObject = new JSONObject(jsonData[0]); /** Getting the parsed data as a List construct */ places = placeJsonParser.parse(jObject); }catch(Exception e){ Log.d("Exception",e.toString()); } return places; } // Executed after the complete execution of doInBackground() method @Override protected void onPostExecute(Place[] places){ mPlaces = places; for(int i=0;i< places.length ;i++){ Place place = places[i]; // Getting latitude of the place double lat = Double.parseDouble(place.mLat); // Getting longitude of the place double lng = Double.parseDouble(place.mLng); LatLng latLng = new LatLng(lat, lng); Marker m = drawMarker(latLng,UNDEFINED_COLOR); // Adding place reference to HashMap with marker id as HashMap key // to get its reference in infowindow click event listener mHMReference.put(m.getId(), place); } } } /** * Drawing marker at latLng with color */ private Marker drawMarker(LatLng latLng,float color){ // Creating a marker MarkerOptions markerOptions = new MarkerOptions(); // Setting the position for the marker markerOptions.position(latLng); if(color != UNDEFINED_COLOR) markerOptions.icon(BitmapDescriptorFactory.defaultMarker(color)); // Placing a marker on the touched position Marker m = mGoogleMap.addMarker(markerOptions); return m; } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
Note : Ensure that “YOUR_BROWSER_KEY” at the line 173 is replaced with the api key obtained in Step 9
20. Update the file AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="in.wptrafficanalyzer.locationnearbyplacesphotos" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <permission android:name="in.wptrafficanalyzer.locationnearbyplacesphotos.permission.MAPS_RECEIVE" android:protectionLevel="signature"/> <uses-permission android:name="in.wptrafficanalyzer.locationnearbyplacesphotos.permission.MAPS_RECEIVE"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-feature android:glEsVersion="0x00020000" android:required="true"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="in.wptrafficanalyzer.locationnearbyplacesphotos.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR_ANDROID_API_KEY"/> </application> </manifest>
Note : Ensure that “YOUR_BROWSER_KEY” at the line 44 is replaced with the api key obtained in Step 8
21. Screenshots of the application in Android 4.0.4 ( Ice Cream Sandwich )
22. Screenshots of the application in Android 2.3.6 ( Ginger Bread )
23. Download Source code