I want to obtain the users current location within a DialogFragment and pass all data to a SQLite databse. In my DoInBackground I get the current location which is working perfectly
I want to set a TextView of long and lat, how can I pass the value out my AysncTask and back to my dialog
protected getLocation doInBackground(String... params) {
}
protected void onPostExecute(getLocation result) {
}
}
I want to pass the value in the outer class so I can put the data in sql
public Dialog onCreateDialog(Bundle savedInstanceState){
final AlertDialog.Builder build = new AlertDialog.Builder(getActivity());
text = (TextView) view.findViewById(R.id.insert_long);
text2 = (TextView) view.findViewById(R.id.insert_lat);
build.setView(view);
db = new DBHelper(getActivity());
db.open();
build.setPositiveButton(R.string.add, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
}
});
The three types used by an asynchronous task are the following:
Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the
background computation.
Result, the type of the result of the background computation.
So you need pass Double[] or your custom structure wraping lat,lon as result.
private class MyTask extends AsyncTask<Void, Void, Double[]>
And implement onPostExecute(Double[] result) method.
You can specify the return type of the method doInBackground(...) when declaring the class.
Like this:
private class LocationReceiver extends AsyncTask<String, Void, double[]> {
protected String doInBackground(String... params) {
try {
LocationManager loca = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
double longitude = location.getLongitude();
double latitude = location.getLatitude();
return new double[] {longitude, latitude};
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void onPostExecute(double[] resultArray) {
// Do something with the returned location
double lon = resultArray[0];
double lat = resultArray[1];
}
}
Create a custom class with latitude and longitude variables :
class LatLng {
public final double latitude;
public final double longitude;
LatLng(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
}
Now return LatLng object from doInBackground method for getting both values in onPostExecute method:
protected LatLng doInBackground(String... params) {
...
double longitude = location.getLongitude();
double latitude = location.getLatitude();
return new LatLng(location.getLatitude(),location.getLongitude());
}
And change LocationTask class as:
private static class LocationTask extends AsyncTask<Location,
Void, getLocation> {
....
#Override
protected getLocation doInBackground(String... params) {
// your code here
}
#Override
protected void onPostExecute(getLocation result) {
text = (TextView) context.findViewById(R.id.textName);
text.setText(result.latitude +"--"+result.longitude);
}
}
Related
So I am new to programming, what I'm trying to do is to make an android app that will give to the client the nearest and fastest way to go the cinema/gas station/market. The problem with that is that first I need to find the nearest places via google api get the lats and lngs and then use them to direction api.
So what I have done is this:
GetNearbyPlaces.java
public class GetNearbyPlaces extends AsyncTask<Object, String, String>
{
private String googleplaceData, url;
private GoogleMap mMap;
#Override
protected String doInBackground(Object... objects)
{
mMap = (GoogleMap) objects[0];
url = (String) objects[1];
DownloadUrl downloadUrl = new DownloadUrl();
try
{
googleplaceData = downloadUrl.ReadTheURL(url);
}
catch (IOException e)
{
e.printStackTrace();
}
return googleplaceData;
}
#Override
protected void onPostExecute(String s)
{
List<HashMap<String, String>> nearbyPlacesList = null;
DataParser dataParser = new DataParser();
nearbyPlacesList = dataParser.parse(s);
DisplayNearbyPlaces(nearbyPlacesList);
super.onPostExecute(s);
Log.d("Message","telos execute ");
}
private void DisplayNearbyPlaces(List<HashMap<String, String>> nearbyPlacesList)
{
for (int i=0; i<nearbyPlacesList.size();
{
Log.d("Message","mesa stin for ");
MarkerOptions markerOptions = new MarkerOptions();
HashMap<String, String> googleNearbyPlace = nearbyPlacesList.get(i);
String nameOfPlace = googleNearbyPlace.get("place_name");
String vicinity = googleNearbyPlace.get("vicinity");
double lat = Double.parseDouble(googleNearbyPlace.get("lat"));
double lng = Double.parseDouble(googleNearbyPlace.get("lng"));
LatLng latLng = new LatLng(lat, lng);
markerOptions.position(latLng);
markerOptions.title(nameOfPlace + " : " + vicinity);
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW));
mMap.addMarker(markerOptions);
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(10));
}
}
}
GoogleUserMaps.java
case R.id.gasstation_nearby:
mMap.clear();
mMap.addMarker(userLocMarkerOptions);
mMap.setTrafficEnabled(true);
url = getUrl(latitude,longitude,gasStation);
transferData[0] = mMap;
transferData[1] = url;
Log.d("Message","Prin kanei execute ");
getNearbyPlaces.execute(transferData);
Log.d("Message","afou kanei execute ");
Toast.makeText(this, "Searching for Nearby Gas Stations.", Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Showing for Nearby Gas Stations.", Toast.LENGTH_SHORT).show();
break;
I want to add something inside DisplayNearbyPlaces a public variable in order to get the lats and lngs but when I use it after the getNearbyPlaces.execute(transferData).get(); of GoogleUserMaps.java it gives me 0 result. I can't understand AsyncTask. Is there any way that I can wait until
getNearbyPlaces.execute(transferData).get(); finishes the execute in order to get the lats and lngs ?
Thank you in advance !
my logcat
I want to get the result after the execute finishes as I show you in the image bellow
Async task runs in a seperate thread than UI thread. It would be better if you try to use a Callback interface and when onPost of Async task is called perform the action in that callback
#Strack I am posting code example of interface
`
public interface PlaceListener{
void searchStarted();
void searchEnded();
}
public class GetNearbyPlaces extends AsyncTask<Object, String, String>
{
private String googleplaceData, url;
private GoogleMap mMap;
private PlaceListener placeListener;
public GetNearbyPlaces(PlaceListener placeListener){
this.placeListner = placeListener;
}
//onPreExecute(){ placeListner.searchStarted();}
#Override
protected String doInBackground(Object... objects)
{
mMap = (GoogleMap) objects[0];
url = (String) objects[1];
DownloadUrl downloadUrl = new DownloadUrl();
try
{
googleplaceData = downloadUrl.ReadTheURL(url);
}
catch (IOException e)
{
e.printStackTrace();
}
return googleplaceData;
}
#Override
protected void onPostExecute(String s)
{
placeListner.serachEnded();
List<HashMap<String, String>> nearbyPlacesList = null;
DataParser dataParser = new DataParser();
nearbyPlacesList = dataParser.parse(s);
DisplayNearbyPlaces(nearbyPlacesList);
super.onPostExecute(s);
Log.d("Message","telos execute ");
}
}
`
Implement the PlaceListener in Caller Activity and perform your desired task in searchEnded. You can make the parameters of your interface methods according to your desired data you want to pass
ok. create a new call back:
public interface MyCallBack {
void myTaskDone(List<HashMap<String, String>> nearbyPlacesList);
}
create one in your activity:
MyCallBack myCallBack = new MyCallBack() {
#Override
public void myTaskDone(List<HashMap<String, String>> nearbyPlacesList) {
DisplayNearbyPlaces(nearbyPlacesList);
}
};
send a reference to the Aynctask:
getNearbyPlaces.execute(transferData, map, new MyCallBack() {
#Override
public void myTaskDone(List<HashMap<String, String>> nearbyPlacesList) {
DisplayNearbyPlaces(nearbyPlacesList);
}
});
complete code:
public interface MyCallBack {
void myTaskDone(List<HashMap<String, String>> nearbyPlacesList);
}
public class GetNearbyPlaces extends AsyncTask<Object, String, String> {
private String googleplaceData;
private String url;
private GoogleMap mMap;
private MyCallBack myCallBack;
public GetNearbyPlaces(String url, GoogleMap mMap, MyCallBack myCallBack) {
this.url = url;
this.mMap = mMap;
this.myCallBack = myCallBack;
}
#Override
protected String doInBackground(Object... objects) {
DownloadUrl downloadUrl = new DownloadUrl();
try {
googleplaceData = downloadUrl.ReadTheURL(url);
} catch (IOException e) {
e.printStackTrace();
}
return googleplaceData;
}
#Override
protected void onPostExecute(String s) {
List<HashMap<String, String>> nearbyPlacesList = null;
DataParser dataParser = new DataParser();
nearbyPlacesList = dataParser.parse(s);
myCallBack.myTaskDone(nearbyPlacesList);
}
}
private void DisplayNearbyPlaces(List<HashMap<String, String>> nearbyPlacesList) {
/// your code
}
MyCallBack myCallBack = new MyCallBack() {
#Override
public void myTaskDone(List<HashMap<String, String>> nearbyPlacesList) {
DisplayNearbyPlaces(nearbyPlacesList);
}
};
How to call it:
//.....
transferData[0] = mMap;
transferData[1] = url;
Log.d("Message","Prin kanei execute ");
GetNearbyPlaces getNearbyPlaces = new GetNearbyPlaces(transferData, map, myCallBack);
getNearbyPlaces.execute();
//or:
GetNearbyPlaces getNearbyPlaces = new GetNearbyPlaces(transferData, map, new MyCallBack() {
#Override
public void myTaskDone(List<HashMap<String, String>> nearbyPlacesList) {
DisplayNearbyPlaces(nearbyPlacesList);
}
});
getNearbyPlaces.execute();
I am trying to fetch latitude and longitude from mysql database using AsyncTask and show it on Map.I have created a class which gets the location from database
here is the method which returns the location from database
public Location addEmployee() {
class AddEmployee extends AsyncTask<Void, Void, String> {
//ProgressDialog loading;
/* #Override
protected void onPreExecute() {
super.onPreExecute();
loading = ProgressDialog.show(MainActivity.this, "Retreiving...", "Wait...", false, false);
}*/
#Override
protected void onPostExecute(String success) {
// super.onPostExecute(success);
//loading.dismiss();
try {
parseJSON(success);
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
protected String doInBackground(Void... v) {
HashMap<String, String> params = new HashMap<>();
params.put("busid", busid);
RequestHandler rh = new RequestHandler();
String res = rh.sendPostRequest("https://tkajbaje.000webhostapp.com/php/busid.php", params);
return res;
}
public void parseJSON(final String success) throws JSONException {
JSONObject jsonObject;
jsonObject = new JSONObject(success);
if (jsonObject.has("Latitude")) {
location.setLatitude(Double.valueOf(jsonObject.getString("Latitude")));
}
if (jsonObject.has("Longitude")) {
location.setLongitude(Double.valueOf(jsonObject.getString("Longitude")));
}
}
}
AddEmployee ae = new AddEmployee();
ae.execute();
return(location);
}
I have another activity which gets the location from the above function and shows it on map.here is the code
public void onMapReady(GoogleMap googleMap) {
// Add a marker in Sydney, Australia,
// and move the map's camera to the same location.
Bundle extras = getIntent().getExtras();
String busid=String.valueOf(1);
Location location;
MainActivity activity=new MainActivity(busid);
location=activity.addEmployee();
double Latitude=location.getLatitude();
Toast.makeText(MapsMarkerActivity.this,String.valueOf(Latitude), Toast.LENGTH_LONG).show();
double Longitude=location.getLongitude();
LatLng sydney = new LatLng(Latitude, Longitude);
googleMap.addMarker(new MarkerOptions().position(sydney)
.title("Bus location"));
googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}
But the latitude and longitude always happen to be 0.0.
Cuz, it starts the AsyncTask and return the location object(whatever the state of that object is). it will not wait for AsyncTask to complete the execution.
Solution:-
You can create an interface in that class and execute in onPostExecute() implement the Interface in activity or use it Anonymously with Class object. Now, whenever it callbacks you can do rest of the work.
I don't see where the location is defined, however it looks like you are mixing asynchronous and synchronous code.
AddEmployee ae = new AddEmployee();
ae.execute();
return(location);
In this part, you invoke an asynchronous task which will assign location a new value if the task is successful, however the keyword here is asynchronous, here location will return before Async Task is completed. You can create a Listener and call it in onPostExecute.
MainActivity activity=new MainActivity(busid);
location=activity.addEmployee();
Here, I strongly recommend making a new class and putting addEmployee there (and other logic that is not specific to the Activity). Creating a new activity with new keyword is not a good approach.
How do I return a List correctly?
I am programming an App with OSMdroid and I want to use the variables "longitude" and "latitude" of the class "Place"(on the bottom of this Post) to ultimately use them in the "onPostExecute" method, right where I set the "PLACEHOLDERS".
Android Studio wants me to alter the line "return loadXmlFromNetwork(urls[0]);", which executes the code below, but I dont know how exactly (The methods below are in the same class).
private class DownloadXmlTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
try {
//Here I want to recieve the list
return loadXmlFromNetwork(urls[0]);
} catch (IOException e) {
return getResources().getString(R.string.connection_error);
} catch (XmlPullParserException e) {
return getResources().getString(R.string.xml_error);
}
}
#Override
protected void onPostExecute(List<Place> result) {
MapView map = (MapView) findViewById(R.id.map);
IMapController mapController = map.getController();
mapController.setZoom(17);
//Here I want to use the latitude and longitude variables of the List
GeoPoint myLocation = new GeoPoint(PLACEHOLDER(latitude), PLACEHOLDER(longitude));
mapController.animateTo(myLocation);
}
}
This is where I recieve the list for the first time:
private List<Place> loadXmlFromNetwork(String urlString) throws XmlPullParserException, IOException {
InputStream stream = null; // Instantiate the parser
XMLParser XMLParser = new XMLParser();
List<Place> places = null;
try {
stream = downloadUrl(urlString);
places = XMLParser.parse(stream); // Makes sure that the InputStream is closed after the app is finished using it.
} finally {
if (stream != null) {
stream.close();
}
}
return places;
}
This is my Place class:
public class Place {
private String longitude;
private String latitude;
private String place_id;
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getPlace_id() {
return place_id;
}
public void setPlace_id(String place_id) {this.place_id = place_id;}
#Override
public String toString() {
return "ID: " + place_id + "\n" + "Longitude: " + longitude + "\n" + "Latitude: " + latitude;
}
The three parametric types of the AsyncTask are AsyncTask<Params, Progress, Result>
(See the AsyncTask documentation)
If you want to have a List<Place> as a result, you must replace
private class DownloadXmlTask extends AsyncTask<String, Void, String> {
with
private class DownloadXmlTask extends AsyncTask<String, Void, List<Place>> {
Your doInBackground() method must then return a List<Place> instead of a String. The line where you call loadXmlFromNetwork(urls[0]) will then work since loadXmlFromNetwork() do returns a List<Place>, but the two other return lines in your catches clauses won't compile anymore since they return String. You must change them, and return null, for example.
Edit: As #Code-Apprentice said, the exception shouldn't just be ignored. You could use boolean flags in order to check them later.
private class DownloadXmlTask extends AsyncTask<String, Void, List<Place>> {
private boolean mConnectionError;
private boolean mXMLError;
#Override
protected List<Place> doInBackground(String... urls) {
try {
//Here I want to recieve the list
return loadXmlFromNetwork(urls[0]);
} catch (IOException e) {
mConnectionError = true;
return null;
} catch (XmlPullParserException e) {
mXMLError = true;
return null;
}
}
#Override
protected void onPostExecute(List<Place> result) {
if (result != null) {
MapView map = (MapView) findViewById(R.id.map);
IMapController mapController = map.getController();
mapController.setZoom(17);
//Here I want to use the latitude and longitude variables of the List
GeoPoint myLocation = new GeoPoint(PLACEHOLDER(latitude), PLACEHOLDER(longitude));
mapController.animateTo(myLocation);
} else {
// An error happened, check mConnectionError and
// mXMLError in order to display an error message.
}
}
}
The easiest fix is to change
private class DownloadXmlTask extends AsyncTask<String, Void, String>
to
private class DownloadXmlTask extends AsyncTask<String, Void, List<Place>>
The last parameter for AsyncTask is the result type. You will need a different way to communicate error situations. For example you can add some boolean fields to use as flags and appropriate gettters to access them. Besides, the AsyncTask should not be responsible for error messages displayed in the UI. This violates the Single Responsibility Principle.
I'm working on a small app and have implemented Google Maps and Places api. Currently i'm able to see all my markers on the map and clustering working fine. I'm able to zoom in the clusters open up and able to see the markers. I have a spinner that has different types and once selected that type is passed to the places search string.
This is my maps code that includes the clustering:
public class MapsActivity extends FragmentActivity implements LocationListener,ClusterManager.OnClusterItemInfoWindowClickListener<MyItem> {
GoogleMap mMap;
double myLatitude = 0;
double myLongitude = 0;
HashMap<String, String> mMarker = new HashMap<String, String>();
PlaceJSONParser placeJsonParser = new PlaceJSONParser();
private ClusterManager<MyItem> mClusterManager;
protected MyItem clickedClusterItem;
String[] placeType;
String[] placeTypeName;
Spinner spinPlaceType;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mMap = mapFragment.getMap();
onMapReady();
// Array of place types
placeType = getResources().getStringArray(R.array.placeType);
// Array of place type names
placeTypeName = getResources().getStringArray(R.array.placeTypeName);
// Creating an array adapter with an array of Place types
// to populate the spinner
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.spinner_item, R.id.textview, placeTypeName);
// Getting reference to the Spinner
spinPlaceType = (Spinner) findViewById(R.id.spinPlaceType);
// Setting adapter on Spinner to set place types
spinPlaceType.setAdapter(adapter);
spinPlaceType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
int selectedPosition = spinPlaceType.getSelectedItemPosition();
final String type = placeType[selectedPosition];
StringBuilder sb = new StringBuilder(
"https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
sb.append("location=" + myLatitude + "," + myLongitude);
sb.append("&type=" + type);
sb.append("&radius=4000");
sb.append("&key=PLACES_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());
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
StringBuilder sb = new StringBuilder(
"https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
sb.append("location=" + myLatitude + "," + myLongitude);
sb.append("&type=restaurant");
sb.append("&radius=4000");
sb.append("&key=PLACES_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());
}
});
// Will display next 20 places returned form the next_page_token
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab_more);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Finding you some more places.", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
StringBuilder sb = new StringBuilder(
"https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
sb.append("pagetoken=" + placeJsonParser.getNext_Page_token());
sb.append("&key=PLACES_KEY");
// Creating a new non-ui thread task to download Google place json
// data
if (placeJsonParser.getNext_Page_token() == null || placeJsonParser.getNext_Page_token() == ""){
Snackbar.make(view, "No more places left to find.", Snackbar.LENGTH_SHORT)
.setAction("Action", null).show();
}
PlacesTask placesTask = new PlacesTask();
// Invokes the "doInBackground()" method of the class PlaceTask
placesTask.execute(sb.toString());
}
});
mMap.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker marker) {
Intent detailsIntent = new Intent(getBaseContext(), PlaceDetailsActivity.class);
String reference = mMarker.get(marker.getId());
marker.getPosition();
detailsIntent.putExtra("reference", reference);
detailsIntent.putExtra("markerLat", myLatitude);
detailsIntent.putExtra("markerLong", myLongitude);
startActivity(detailsIntent);
}
});
}
public void onMapReady(){
// Enabling MyLocation in Google Map
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setCompassEnabled(true);
mMap.getUiSettings().setZoomControlsEnabled(true);
// Getting LocationManager object from System Service
// LOCATION_SERVICE
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
// Creating a criteria object to retrieve provider
Criteria criteria = new Criteria();
// Getting the name of the best provider
String provider = locationManager.getBestProvider(criteria, true);
// Getting Current Location From GPS
Location location = locationManager.getLastKnownLocation(provider);
// onLocationChanged(location);
if (location != null) {
onLocationChanged(location);
}
}
/**
* A method to download json data from url
*/
private String downloadUrl(String strUrl) throws IOException {
String referer ="";
StringBuilder jsonResults = new StringBuilder();
HttpURLConnection conn = null;
try {
URL url = new URL(strUrl);
// Creating an http connection to communicate with url
conn = (HttpURLConnection) url.openConnection();
if (referer != null) {
conn.setRequestProperty("Referer", referer);
}
InputStreamReader in = new InputStreamReader(conn.getInputStream());
// Load the results into a StringBuilder
int read;
char[] buff = new char[1024];
while ((read = in.read(buff)) != -1) {
jsonResults.append(buff, 0, read);
}
// Displays the list of places found in the terminal.
Log.i("Data", "Places Found: " + jsonResults);
} catch (MalformedURLException e) {
Log.i("Google Places Utility", "Error processing Places API URL");
return null;
} catch (IOException e) {
Log.i("Google Places Utility", "Error connecting to Places API");
return null;
} finally {
if (conn != null) {
conn.disconnect();
}
}
return jsonResults.toString();
}
/**
* 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 the class ParseTask
parserTask.execute(result);
}
}
/**
* A class to parse the Google Places in JSON format
*/
private class ParserTask extends
AsyncTask<String, Integer, List<HashMap<String, String>>> {
JSONObject jObject;
// Invoked by execute() method of this object
#Override
protected List<HashMap<String, String>> doInBackground(
String... jsonData) {
List<HashMap<String, String>> places = null;
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(List<HashMap<String, String>> list) {
// Clears all the existing markers
mMap.clear();
setUpClusterer(list);
}
}
private void setUpClusterer(List<HashMap<String, String>> list) {
// Position the map.
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(myLatitude,myLongitude), 13));
// Initialize the manager with the context and the map.
// (Activity extends context, so we can pass 'this' in the constructor.)
mClusterManager = new ClusterManager<MyItem>(this, mMap);
// Point the map's listeners at the listeners implemented by the cluster
// manager.
mMap.setOnCameraChangeListener(mClusterManager);
mMap.setOnMarkerClickListener(mClusterManager);
mMap.setInfoWindowAdapter(mClusterManager.getMarkerManager());
mMap.setOnInfoWindowClickListener(mClusterManager);
mClusterManager.setOnClusterItemInfoWindowClickListener(this);
mClusterManager
.setOnClusterItemClickListener(new ClusterManager.OnClusterItemClickListener<MyItem>() {
#Override
public boolean onClusterItemClick(MyItem item) {
clickedClusterItem = item;
return false;
}
});
// Add cluster items (markers) to the cluster manager.
addItems(list);
mClusterManager.getMarkerCollection().setOnInfoWindowAdapter(
new MyCustomAdapterForItems());
}
public class MyCustomAdapterForItems implements GoogleMap.InfoWindowAdapter {
private final View myContentsView;
MyCustomAdapterForItems() {
myContentsView = getLayoutInflater().inflate(
R.layout.info_window, null);
}
#Override
public View getInfoWindow(Marker marker) {
TextView tvTitle = ((TextView) myContentsView
.findViewById(R.id.txtTitle));
TextView tvSnippet = ((TextView) myContentsView
.findViewById(R.id.txtSnippet));
tvTitle.setText(clickedClusterItem.getTitle());
tvSnippet.setText(clickedClusterItem.getSnippet());
return myContentsView;
}
#Override
public View getInfoContents(Marker marker) {
return null;
}
}
private void addItems(List<HashMap<String, String>> list) {
double latitude;
double longitude;
for (int i = 0; i < list.size(); i++) {
HashMap<String, String> hmPlace = list.get(i);
// Getting latitude of the place
latitude = Double.parseDouble(hmPlace.get("lat"));
// Getting longitude of the place
longitude = Double.parseDouble(hmPlace.get("lng"));
String name = hmPlace.get("place_name");
// Getting vicinity
String vicinity = hmPlace.get("vicinity");
MyItem offsetItem = new MyItem(latitude, longitude, hmPlace.get("reference"), name, vicinity);
mClusterManager.addItem(offsetItem);
}
}
public void onClusterItemInfoWindowClick(MyItem item) {
Intent placesIntent = new Intent(getBaseContext(), PlaceDetailsActivity.class);
String reference = item.getReference();
placesIntent.putExtra("name", item.getTitle());
placesIntent.putExtra("reference", reference);
placesIntent.putExtra("sourcelat", myLatitude);
placesIntent.putExtra("sourcelng", myLongitude);
startActivity(placesIntent);
}
#Override
public void onLocationChanged(Location location) {
myLatitude = location.getLatitude();
myLongitude = location.getLongitude();
LatLng myLocation = new LatLng(myLatitude, myLongitude);
mMap.moveCamera(CameraUpdateFactory.newLatLng(myLocation));
mMap.animateCamera(CameraUpdateFactory.zoomTo(13));
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}
my myItem class to get info for the markers:
package com.example.tariq.outandabout;
import com.google.android.gms.maps.model.LatLng;
import com.google.maps.android.clustering.ClusterItem;
public class MyItem implements ClusterItem {
LatLng mPosition;
private String reference,placeTitle,snippet;
public MyItem(double lat, double lng,String val,String title, String snip) {
mPosition = new LatLng(lat, lng);
reference=val;
placeTitle=title;
snippet = snip;
}
#Override
public LatLng getPosition() {
// TODO Auto-generated method stub
return mPosition;
}
public String getReference() {
// TODO Auto-generated method stub
return reference;
}
public String getTitle() {
// TODO Auto-generated method stub
return placeTitle;
}
public String getSnippet() {
// TODO Auto-generated method stub
return snippet;
}
}
Currently only red markers are getting displayed but I was wondering if there is a way to have a different markers depending on the type selected from the spinner, For example if I select Hospital then the markers are shown as little hospital icons, if I select ATM, then a little ATM icon appears.
Any help will be appreciated.
Firstly you have to store all the info you need (at this situation just LatLng and marker icon) insite ClusterItem object.
public class MarkerItem implements ClusterItem {
private String title;
private String snippet;
private LatLng latLng;
private BitmapDescriptor icon;
public MarkerItem(MarkerOptions markerOptions) {
this.latLng = markerOptions.getPosition();
this.title = markerOptions.getTitle();
this.snippet = markerOptions.getSnippet();
this.icon = markerOptions.getIcon();
}
#Override
public LatLng getPosition() {
return latLng;
}
public String getTitle() {
return title;
}
public String getSnippet() {
return snippet;
}
public void setLatLng(LatLng latLng) {
this.latLng = latLng;
}
public BitmapDescriptor getIcon() {
return icon;
}
public void setIcon(BitmapDescriptor icon) {
this.icon = icon;
}
}
The next step would be to make cluster renderer show your icon instead of default maker icon. To achieve that, you need to extend DefaultClusterRenderer object:
public class ClusterRenderer extends DefaultClusterRenderer<MarkerItem> {
public ClusterRenderer(Context context, GoogleMap map, ClusterManager<MarkerItem> clusterManager) {
super(context, map, clusterManager);
clusterManager.setRenderer(this);
}
#Override
protected void onBeforeClusterItemRendered(MarkerItem markerItem, MarkerOptions markerOptions) {
if (markerItem.getIcon() != null) {
markerOptions.icon(markerItem.getIcon()); //Here you retrieve BitmapDescriptor from ClusterItem and set it as marker icon
}
markerOptions.visible(true);
}
}
Finally, you have to initialize the clusterRenderer and markerItems
ClusterManager clusterManager = new ClusterManager<>(context, googleMap);
ClusterRenderer clusterRenderer = new ClusterRenderer<>(activity, googleMap, clusterManager); // not needed to use clusterManager.setRenderer method since i made it in constructor
MarkerOptions markerOptions = new MarkerOptions()
.position(new LatLng(latitude, longitude))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.your_resource_icon));
MarkerItem markerItem = new MarkerItem(markerOptions);
clusterManager.addItem(markerItem);
You can implement your own logic, which icon you want to pass to markerItem here.
EDIT
To pass different icons, you could create a separate method for that
Example:
public MarkerOptions getMarkerOptions(LatLng latLng, String title, String snippet, int iconRes) {
return new MarkerOptions()
.title(title)
.snippet(snippet)
.position(latLng)
.icon(BitmapDescriptorFactory.fromResource(iconRes));
}
EDIT 2
I updated MarkerItem class to suit your needs, replace your MyItem class with MarkerItem class. Add your items using this class and update it to suit your needs
I tried to use reverse geocoding with AsyncTask but but the parameters of latitude and longitude that passes through the method doInBackground() are not happening correctly. any idea?
public class SitesAdapter extends ArrayAdapter<StackSite> {
public static Double lat;
public static Double lng;
#Override
public View getView(int pos, View convertView, ViewGroup parent){
...
lat = -1.80;
lng = -80.20;
...
}
public void start(){
new GetAddressTask(mContext).execute(lat, lng);
}
public static class GetAddressTask extends AsyncTask<Double, Void, String> {
//mContext
#Override
protected String doInBackground(Double... params) {
Geocoder gc = new Geocoder(mContext, Locale.getDefault());
List<Address> list = null;
String city = "";
double latitude = params[0];
double longitude = params[1];
try {
list = gc.getFromLocation(lat, lng, 1);
} catch (IOException e) {
e.printStackTrace();
}
if (list != null && list.size() > 0) {
Address address = list.get(0);
city = String.format("%s, %s", address.getAdminArea(), address.getCountryName());
}
return city;
}
#Override
protected void onPostExecute(String city) {
tituloTxt.setText(city);
}
}
}
error:
11-21 15:10:24.409: E/Trace(24502): error opening trace file: No such file or directory (2)
Well after so only had to do this to pass the coordinates. First add coordinate to constructor LatLng(double latitude, double longitude) and pass the parameters.
lat = -1.80;
lng = -80.20;
LatLng latlng = new LatLng(lat, lng);
new GetAddressTask(mContext).execute(lat, lng);
Then inside the doInbackground method get parameters.
public static class GetAddressTask extends AsyncTask<LatLng, Void, String> {
//mContext
#Override
protected String doInBackground(LatLng... params) {
Geocoder gc = new Geocoder(mContext, Locale.getDefault());
List<Address> list = null;
String city = "";
LatLng loc = params[0]; //Get all parameters: latitude and longitude
try {
list = gc.getFromLocation(loc.latitude, loc.longitude, 1); //get specific parameters
} catch (IOException e) {
e.printStackTrace();
}
if (list != null && list.size() > 0) {
Address address = list.get(0);
city = String.format("%s, %s", address.getAdminArea(), address.getCountryName());
return city;
}else{
return "City no found";
}
}
#Override
protected void onPostExecute(String city) {
tituloTxt.setText(city);
}
}
before calling execute method, u can just create a constructor ,in which you can initialize your class data members which can be further used in doInBackground(..).
Add two variables to your class and set them when you create async task, then use them in method. Simple.
public class GetAddressTask extends AsyncTask<String, Void, String> {
Context mContext;
float lat,lin;
public void setLat(int lat){...}
//rest of class
of course you can make everything static (fields and setters).
Edit.
If you are calling execute with some parameters, remember that your values have to be set before calling execute.