So I am extending an ItemizedOverlay, and using a rest query to make an async http request to web service where I can get the coordinates of lots of push pins.
Once the handler gets the async http request I do the following (maybe not the best solution - ie. clearing all records all the time). But I am open to suggestions (hence the post)..
Basically here is the code flow (I have a list view & map view on a flipper and want to keep them in sync - hence the arrayAdapter;
locationRecords.clear(); // ArrayList<LocationRecord>
updateScreen(jArray); // jSONArray jArray
arrayAdapter.notifyDataSetChanged();
updateOverlay();
private synchronized void updateOverlay() {
// Clear the previous overlay of map push pins (don't want to keep adding new overlays)
Iterator<Overlay> listofOverlays = mapView.getOverlays().iterator();
while (listofOverlays.hasNext()) {
Overlay tempOverlay = listofOverlays.next();
if (tempOverlay.getClass().equals(MunzeeOverlay.class)) {
mapView.getOverlays().remove(tempOverlay);
}
this.notify();
}
MyOverlay overlay = new MyOverlay(MapTools.getGreenMarker(mContext),mapView);
Iterator<LocationRecord> mapList = locationRecords.iterator();
while (mapList.hasNext()) {
overlay.addOverlay(mapList.next().getOverlayItem());
}
mapView.getOverlays().add(overlay);
}
protected void updateScreen(JSONArray jArray) {
if ( jArray != null ) {
for ( int i = 0; i < jArray.length(); i++ ) {
try {
JSONObject myArray = jArray.getJSONObject(i);
locationRecords.add(new LocationRecord(myArray,mContext));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
My thought is on the myOverlay that I can do a check when I addOverlay w/ an equiv check and make sure it is not already there, that way i would not need to delete the overlay on the map?
I also am seeing some ConcurrentModificationExceptions in updateOverlay (I suppose that could have to do w/ clearing the locationRecords & updatingScreen not in a synchronized manner.. Sooo..
1) Any suggestions for improving map pin performance, and not seeming to freeze the map while it is updating the overlay
2) Any suggestions on fixing the ConcurrentModificationExceptions?
Have one overlay with N pins. Near as I can tell, you have N overlays with one pin each. This is bad.
When your data arrives, call populate() on the one-and-only overlay to have Android reload all of the markers -- you do not need to clear anything yourself.
Related
I have problem about my gps and plot polygon
I collect GPS every second from
Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
and put it to realm database
(So I things do I not good idea)
Maybe should accumulate every 10 meters
image below is result I got
my problems
Polygon look alike the PASTA instead of area.
My gps can jump over to another building(GPS is not stable)
help recommend me please.
ArrayList<LatLng> coordList = new ArrayList<LatLng>();
#Cleanup Realm realm = Realm.getDefaultInstance();
RealmResults<PolygonAreas> PlotPolygon = realm.where(PolygonAreas.class).findAll();
if (PlotPolygon.size() > 0) {
for (PolygonAreas Polypoint : PlotPolygon) {
coordList.add(new LatLng(Polypoint.getLatitude(), Polypoint.getLongitude()));
try {
Runnable addPolygon = new CellTowerMarkerGoogle.AddPolygon(mMap, new PolygonOptions()
.addAll(coordList).fillColor(0x7F80b370).strokeColor(0x7F80b370)
);
getActivity().runOnUiThread(addPolygon);
} catch (Exception e) {
log.debug("Exception : " + e);
}
}
}
public static class AddPolygon implements Runnable{
private GoogleMap map;
private PolygonOptions options;
public AddPolygon(GoogleMap map,PolygonOptions options){
this.map = map;
this.options = options;
}
#Override
public void run() { map.addPolygon(options);}
}
I found problem
Because my logic incorrect variable addPolygon
every back again it's create new Object polygon(.addAll)
It causes the creation of overloaded objects.
How can I fix it?
I have to destroy the polygon object and recreate it every time.
The value will be updated all the time. I have to destroy and create new polygons every time to update.
Please look at my code to create layer from geojson string and add layer to map:
private GeoJsonLayer createLayerFromGeojson(String json)
{
JSONObject ob = null;
try
{
ob = new JSONObject(json);
}
catch (JSONException e)
{
e.printStackTrace();
}
GeoJsonLayer layer = new GeoJsonLayer(googleMap, ob);
layer.addLayerToMap();
layer.setOnFeatureClickListener(feature -> Utils.showMessage(getActivity(), "Clicked", feature.getProperty("description").toString()));
return layer;
}
Next add 2 layers to map:
String json = /*first geojson string here*/
String json2 = /*another geojson string here*/
createLayerFromGeojson(json);
createLayerFromGeojson(json2);
Problem: When I click on marker or pologon, always description taken from second json (json2) is displayed, even if I click on object created from first json, on first layer.
What's wrong? Any ideas?
If you check the documentation for the method setOnFeatureClickListener it says:
Sets a single click listener for the entire GoogleMap object, that will be called with the corresponding Feature object when an object on the map (Polygon, Marker, Polyline) is clicked.
To me, it seems silly that we cannot have multiple layers with information from different GeoJson. It needs to be a MultiPolygon, MultiLineString or MultiPoint.
Reference: https://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/data/Layer.java#L89
A colleague of mine is currently working on implementing turn by turn directions into an app that is being developed for the company we are working in. I have been tasked with trying to assist him but neither of us have been able to make any progress.
He is using Mapbox to create the map. I have never used mapbox before so I am not much help.
He has code implemented that should give us turn by turn directions but it does not seem to be doing anything whatsoever.
Sorry if I am bringing up old questions or am not stating my situation clearly but this is the best I can explain myself. We have done much searching but nothing we found seems to help.
Here is the code that he has tried using that is supposed to implement turn by turn directions.
private void getRoute(Waypoint origin, Waypoint destination) throws ServicesException {
MapboxDirections client = new MapboxDirections.Builder()
.setOrigin(origin)
.setDestination(destination)
.setProfile(DirectionsCriteria.PROFILE_DRIVING)
.setSteps(true)
// .setOverview(DirectionsCriteria.OVERVIEW_FULL)
.setInstructions(DirectionsCriteria.INSTRUCTIONS_TEXT)
.setAccessToken("pk.eyJ1IjoibnRyY3N2ZyIsImEiOiJCUmc4OHhjIn0.shHWdNg3Q32QUHJ1nOCs3A")
.build();
client.enqueue(new retrofit.Callback<DirectionsResponse>() {
#Override
public void onResponse(Response<DirectionsResponse> response, Retrofit retrofit) {
// You can get the generic HTTP info about the response
Log.d(TAG, "Response code: " + response.code());
if (response.body() == null) {
Log.e(TAG, "No routes found, make sure you set the right user and access token.");
return;
} else if (response.body().getRoutes().size() < 1) {
Log.e(TAG, "No routes found");
return;
}
}
#Override
public void onFailure(Throwable t) {
Log.e(TAG, "Error: " + t.getMessage());
Toast.makeText(MainActivity.this, "Error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
}
public void onResponse(Response<DirectionsResponse> call, Response<DirectionsResponse> response) {
// You can get the generic HTTP info about the response
Log.d(TAG, "Response code: " + response.code());
if (response.body() == null) {
Log.e(TAG, "No routes found, make sure you set the right user and access token.");
return;
} else if (response.body().getRoutes().size() < 1) {
Log.e(TAG, "No routes found");
return;
}
drawRoute(currentRoute);
}
private void drawRoute(DirectionsRoute route) {
// Convert LineString coordinates into LatLng[]
LineString lineString = LineString.fromPolyline(route.getGeometry(), Constants.OSRM_PRECISION_V5);
List<Position> coordinates = lineString.getCoordinates();
LatLng[] points = new LatLng[coordinates.size()];
for (int i = 0; i < coordinates.size(); i++) {
points[i] = new LatLng(
coordinates.get(i).getLatitude(),
coordinates.get(i).getLongitude());
}
Polyline polyline = mMapboxMap.addPolyline(new PolylineOptions()
.add(points)
.color(Color.RED)
.width(5));
directionsOn = true;
}
Any help would be very much appreciated.
Thanks in advance.
I'd highly recommend changing from Directions v4 to v5 found in Mapbox Java. Once you make the switch, you can work off this example found on our website. Make sure you are also passing in coordinates in the correct order, longitude is given first followed by latitude.
Dear friend mapbox provides detailed document with sample code snippets as well.
I have build a working app for my requirement by following mapbox turn by turn navigation documents.
please follow the link and let me know if you face any issues.
Link : https://www.mapbox.com/android-docs/navigation/overview/navigation-ui/
Here you can use NavigationView component to customise the mapbox turn by turn features.
I create a room and it gets successfully made. And my onRoomCreated method gets called...
#Override
public void onRoomCreated(int statusCode, Room room) {
mRoomId = room.getRoomId();
Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(gApiClient, room, 2);
startActivityForResult(i, RC_WAITING_ROOM);
}
Then in my onActivityResult...
Room r = data.getExtras().getParcelable(Multiplayer.EXTRA_ROOM);
ArrayList<String> invitees = new ArrayList<String>();
for (Participant p : r.getParticipants()) {
invitees.add(p.getPlayer().getPlayerId()); //<---NULL POINTER!
}
I get that null pointer. Why?
EDIT: The android docs say this about the getPlayer() method...
Returns the Player that this participant represents. Note that this may be null if the identity of the player is unknown. This occurs in automatching scenarios where some players are not permitted to see the real identity of others.
That is why I am getting null, because my room is through auto-matching.
Now the question is. How can I create a turnbasedgame using only participant IDs? Not Player IDs
Now that I see what you are asking more clearly (my fault, not yours), here is how I do it:
(for clarification I use LibGDX, so may be some interface stuff you don't need, and I am still using GamesClient not the new API methods, but is for all intents the same)
First, the final call I look to start my game is onRoomConnected
#Override
public void onRoomConnected(int statusCode, Room room) {
//dLog("onRoomConnected");
mRoomCurrent = room;
mParticipants = room.getParticipants();
mMyID = room.getParticipantId(aHelper.getGamesClient().getCurrentPlayerId());
//dLog("The id is " + mMyID);
try {
bWaitRoomDismissedFromCode = true;
finishActivity(RC_WAITING_ROOM);
} catch (Exception e) {
//dLog("would have errored out in waiting room");
}
//tell the Game the room is connected
if (statusCode == GamesClient.STATUS_OK) {
theGameInterface.onRoomConnected(room.getParticipantIds(), mMyID, room.getCreationTimestamp() );
} else {
leaveRoom();
}
}
So, now have all the participantIDs.. now in my Game code (where I sent that List of Ids), I sort the list of IDs so that in determining Player order, it is the same methodology for all Players. First I build my opponents.
private void buildOpponents() {
// this creates a new opponent with a View on the Stage()
//sort the participants the same for all players
sortParticipantIDs();
for (String s : mParticipantIds) {
if(s.contains(mMyID) || mMyID.contains(s)) continue;
newOpponentWindow ow = new newOpponentWindow(s, MyAssetManager.getMySkin(), getStage());
Opponent o = new Opponent(this, s);
mapOpponents.put(s, o);
o.setWindow(ow);
getStage().addActor(ow);
}
setOpponentWindowPositions();
}
Then after some more setup I start Play and my first Time through, I have chosen that whoever is the top ID gets the honor of starting (I find this randomizes play enough, without having to do another method.. .but you can let the top ID do another method, and send that out to the other Players) Note this checks over my Opponents to determine Starting Player if someone leaves the room later in the game as well.
private boolean determineIfStartingBidder() {
Collections.sort(mParticipantIds);
// now look thru list
// if the number is mine then return true
// if the number is not mine.. and opponent is not Out of Game or Disconnected.. then return false
for (String s : mParticipantIds) {
if(s.contains(mMyID) || mMyID.contains(s)){
return true;
}
if(mapOpponents.get(s).getCurrentState() == currentState.DISCONNECTED || mapOpponents.get(s).getCurrentState() == currentState.OUTOFGAME ||
mapOpponents.get(s).getCurrentState() == currentState.LOSTGAME) {
continue;
}
return false;
}
return false;
}
Then in your game logic, just go through your ParticipantID list in whatever manner makes sense to pass the baton around! This works well, since all the calls for passing messages require the ParticipantID, and are there for easy grab n go!
Prior Answer Below ------------------------------------------------
try
data.getParcelableExtra(Multiplayer.EXTRA_ROOM);
no need for the getExtras
I am following a tutorial here https://code.google.com/p/osmbonuspack/wiki/Tutorial_1 but I have encountered an error that it doesn't show the correct route correctly. It just shows a straight line from Point A to Point B.
What I want to achieve is to show the correct route from these points. I'm guessing the error is that it doesn't recognize any nodes to go through.
A similar question has been also asked and I am assuming I have the same problem if I haven't explained my question well.
Similar question can be found here: OSMDroid Routing problems when following a tutorial
Here is a part of my code using RoadManager
Here is a part of the code.
try {
//get current longlat
gpsLocator.getLocation();
cur_loc_lat =gpsLocator.getLatitude();
cur_loc_long =gpsLocator.getLongitude();
} catch (Exception e) {
// TODO: handle exception
}
//--- Create Another Overlay for multi marker
anotherOverlayItemArray = new ArrayList<OverlayItem>();
anotherOverlayItemArray.add(new OverlayItem(
"UST", "UST", new GeoPoint( testlat, testlong)));
//--- Create Another Overlay for multi marker
anotherOverlayItemArray.add(new OverlayItem(
locDefine[0], "UST", new GeoPoint( sel_latitude, sel_longitude)));
ItemizedIconOverlay<OverlayItem> anotherItemizedIconOverlay
= new ItemizedIconOverlay<OverlayItem>(
TomWalks.this, anotherOverlayItemArray, myOnItemGestureListener);
myOpenMapView.getOverlays().add(anotherItemizedIconOverlay);
//---
//Add Scale Bar
ScaleBarOverlay myScaleBarOverlay = new ScaleBarOverlay(TomWalks.this);
myOpenMapView.getOverlays().add(myScaleBarOverlay);
try {
//1 Routing via road manager
RoadManager roadManager = new MapQuestRoadManager();
roadManager.addRequestOption("routeType=pedestrian");
/*
roadManager.addRequestOption("units=m");
roadManager.addRequestOption("narrativeType=text");
roadManager.addRequestOption("shapeFormat=raw");
roadManager.addRequestOption("direction=0");
*/
//Then, retrieve the road between your start and end point:
ArrayList<GeoPoint> waypoints = new ArrayList<GeoPoint>();
waypoints.add(new GeoPoint(testlat, testlong));
waypoints.add(new GeoPoint(sel_latitude,sel_longitude)); //end point
Road road = roadManager.getRoad(waypoints);
// then, build an overlay with the route shape:
PathOverlay roadOverlay = RoadManager.buildRoadOverlay(road, myOpenMapView.getContext());
roadOverlay.setColor(Color.GREEN);
//Add Route Overlays into map
myOpenMapView.getOverlays().add(roadOverlay);
myOpenMapView.invalidate();//refesh map
final ArrayList<ExtendedOverlayItem> roadItems =
new ArrayList<ExtendedOverlayItem>();
ItemizedOverlayWithBubble<ExtendedOverlayItem> roadNodes =
new ItemizedOverlayWithBubble<ExtendedOverlayItem>(TomWalks.this, roadItems, myOpenMapView);
myOpenMapView.getOverlays().add(roadNodes);
myOpenMapView.invalidate();//refesh map
int nodesize=road.mNodes.size();
double length = road.mLength;
Drawable marker = getResources().getDrawable(R.drawable.marker_node);
Toast.makeText(TomWalks.this, " Distance : " + length + " Nodes : "+nodesize ,Toast.LENGTH_SHORT).show();
for (int i=0; i<road.mNodes.size(); i++)
{
RoadNode node = road.mNodes.get(i);
ExtendedOverlayItem nodeMarker = new ExtendedOverlayItem("Step "+i, "", node.mLocation, TomWalks.this);
nodeMarker.setMarkerHotspot(OverlayItem.HotspotPlace.CENTER);
nodeMarker.setMarker(marker);
roadNodes.addItem(nodeMarker);
nodeMarker.setDescription(node.mInstructions);
nodeMarker.setSubDescription(road.getLengthDurationText(node.mLength, node.mDuration));
Drawable icon = getResources().getDrawable(R.drawable.marker_node);
nodeMarker.setImage(icon);
}//end for
myOpenMapView.getOverlays().add(roadNodes);
myOpenMapView.invalidate();//refesh map
} catch (Exception e) {
// TODO: handle exception
Toast.makeText(TomWalks.this,e.getMessage(),Toast.LENGTH_SHORT).show();
}
myMapController.setCenter(new GeoPoint( sel_latitude, sel_longitude));
} catch (Exception e) {
// TODO: handle exception
}
}
}
}//===================================================================================================
Let's try to provide a complete answer to this quite frequent question.
Basically, when you get the "straight line", it means that the RoadManager got an error.
So, first of all, in your code, you should check the result of getRoad, this way:
if (road.mStatus != Road.STATUS_OK){
//handle error... warn the user, etc.
}
Now, where this error is coming from?
=> You must search in the logcat. You should find the full url that has been sent, and probably a stacktrace about the error.
I strongly recommend that you copy/paste this full url in a browser , and check the result.
Here are the typical errors, by decreasing probability:
1) You didnt' read carefully the "Important note" at the beginning of the Tutorial_0, and you are trying to do a Network call in the main thread, with an SDK >= 3.0.
=> Read this "Important note".
2) You asked for a route that is not possible (really not possible, or because of weird positions, or because of setting unsupported options).
=> This is easy to check by copy/pasting the full url in a web browser, and looking at the answer.
3) Your device has no network connectivity.
4) The routing service changed its API (this happened, more than once...).
=> Could be checked by copy/pasting the full url in a browser.
In this case, raise an Issue in OSMBonusPack project, so that we can take it into account ASAP.
5) The routing service is down.
=> Easy to check by copy/pasting the full url in a browser.
I think it is better to use AsyncTasks in this case:
/**
* Async task to get the road in a separate thread.
*/
private class UpdateRoadTask extends AsyncTask<Object, Void, Road> {
protected Road doInBackground(Object... params) {
#SuppressWarnings("unchecked")
ArrayList<GeoPoint> waypoints = (ArrayList<GeoPoint>)params[0];
RoadManager roadManager = new OSRMRoadManager();
return roadManager.getRoad(waypoints);
}
#Override
protected void onPostExecute(Road result) {
road = result;
// showing distance and duration of the road
Toast.makeText(getActivity(), "distance="+road.mLength, Toast.LENGTH_LONG).show();
Toast.makeText(getActivity(), "durée="+road.mDuration, Toast.LENGTH_LONG).show();
if(road.mStatus != Road.STATUS_OK)
Toast.makeText(getActivity(), "Error when loading the road - status="+road.mStatus, Toast.LENGTH_SHORT).show();
Polyline roadOverlay = RoadManager.buildRoadOverlay(road,getActivity());
map.getOverlays().add(roadOverlay);
map.invalidate();
//updateUIWithRoad(result);
}
}
then call it new UpdateRoadTask().execute(waypoints);
new Thread(new Runnable()
{
public void run()
{
RoadManager roadManager = new OSRMRoadManager();
ArrayList<GeoPoint> waypoints = new ArrayList<GeoPoint>();
GeoPoint startPoint = new GeoPoint(source_lat, source_longi);
waypoints.add(startPoint);
GeoPoint endPoint = new GeoPoint(desti_lat,desti_longi);
waypoints.add(endPoint);
try
{
road = roadManager.getRoad(waypoints);
}
catch (Exception e)
{
e.printStackTrace();
}
runOnUiThread(new Runnable()
{
public void run()
{
if (road.mStatus != Road.STATUS_OK)
{
//handle error... warn the user, etc.
}
Polyline roadOverlay = RoadManager.buildRoadOverlay(road, Color.RED, 8, context);
map.getOverlays().add(roadOverlay);
}
});
}
}).start();
And i am use two jar files 1)slf4j-android-1.5.8.jar and 2)osmdroid-android-4.2.jar and osmbonuspack library.
A strange error I found regarding this is as follows:
Firstly I mention following line of code for taking directions for the vehicle "BIKE"
((OSRMRoadManager) roadManager).setMean(OSRMRoadManager.MEAN_BY_BIKE);
Now when it was first called it follows the following URL:
https://routing.openstreetmap.de/routed-car/route/v1/driving/68.8889678000,23.2151582000;73.1808008000,22.3110728000?alternatives=false&overview=full&steps=true
Now when calling the second time{same MEAN_BY_BIKE}, it is following this URL:
:https://routing.openstreetmap.de/routed-bike/route/v1/driving/68.8889678000,23.2151582000;73.1808008000,22.3110728000?alternatives=false&overview=full&steps=true
So the issue is that no response is for the "routed-bike" and it is calling automatically itself when called for second time.
So as a solution I changed my code to the following:
((OSRMRoadManager) roadManager).setMean(OSRMRoadManager.MEAN_BY_CAR);
You can check your LogCat for the same.