Android loads dynamically better strategy markers

I have an Android map with google maps that dynamically download tokens from the server based on the user's screen position. For example, if the user moves the map, I just made a request to the server, and I send the borders of the screen, and based on this I get marker data (id and corrdinates), which are later parsed and created for actual pointers. The problem is that when the user returns to the same area (which tokens were previously created), I still make the same request and get the same data (but, obviously, I will not allow this marker to be recreated, so I just start the loop for all markers, they are on the map and check if the identifier of the map marker is equal to the server identifier of the data transfer marker, and if it is equal, I just break the loop)

try { Collection<MarkerItemData> mapMarkers = algorithm.getItems(); JSONObject jsonObject = new JSONObject(strings[0]); JSONArray respondArray = jsonObject.getJSONArray("respond"); list = new ArrayList(); for (int i = 0; i < respondArray.length(); i++) { JSONObject station = respondArray.getJSONObject(i); int id = station.getInt("_id"); boolean skip = false; for (final MarkerItemData m : mapMarkers) { if (m.getId() == id) { skip = true; break; } } } } 

However, I do not think this approach is the best. I also have other ideas that should work (at least I think)

  • send to the screen screen, as well as all marker identifiers that are visible on the screen (I could select all the markers that are in the range of the screen and which identifiers are not within the screen)
  • delete tokens every time from the android application and basically recreate all tokens from the server every time (I personally think this is a bad decision)

So which of these ideas is the best? Any other ideas? (Sorry for my English)

+5
source share
3 answers

Sending screen boundaries to the server, and the identifiers of currently visible markers on the screen is your best bet. But still there are a couple of problems. How do you find all the markers contained in the range indicated by the borders of the screen? What if new tokens arrive on your server or some tokens are removed? Can you come with a support structure in this situation or will you check each point that matches the marker in the database one by one to determine if it is in the range or not? Given all this, you need to find a way to optimize storage and point requests, in other words, the latitude and longitude pairs that markers indicate. You must perform spatial indexing using one of the general spatial index methods.

There are many spatial indexing methods available, and one may be slightly better than the other depending on the use case. To make a long story short, since you need to request a range in this scenario, you must implement a quadrant. A square is called a tree data structure in which each inner node has exactly four children (northwest, northeast, southwest, southeast). If you are not aware of this structure, I believe that you can understand its basics in an hour, but explaining it in detail from scratch will lead to the loss of too much time for me. Therefore, I skip implementation details about quadrants. There are several sources that have already explained this structure much better than I could, and you can easily find an open source library.

I will only give the Java pseudo-hash method for your quadrant to find all the points that are displayed within the borders of the screen, excluding those that are already on the previous screen:

 ArrayList<LatLng> queryRange(QuadLevel level, float[] screenBounds, ArrayList<LatLng> prevPoints) { // Initialize a list to hold the found points ArrayList<LatLng> pointsInRange = new ArrayList<>(); if (!quadtreeBounds.intersects(screenBounds)) return pointsInRange; // Find the points that are in the current quad level for (LatLng point : level.getPoints()) { // If the current point is in screen bounds and it is not contained by prevPoints if (point.isInRange(screenBounds) && !prevPoints.contains(point)) pointsInRange.add(point); } // If there are no children, return if (level.hasNoChildren()) return pointsInRange; // Else, continue to look up children pointsInRange.addAll(queryRange(level.northwest, screenBounds, prevPoints)); pointsInRange.addAll(queryRange(level.northeast, screenBounds, prevPoints)); pointsInRange.addAll(queryRange(level.southwest, screenBounds, prevPoints)); pointsInRange.addAll(queryRange(level.southeast, screenBounds, prevPoints)); return pointsInRange; } 
+2
source

Store all visible markers on the screen in a list or local Db or somewhere and iterate over existing markers in the list if there is no request from the server

+1
source

Extend the HashSet<MarkerOptions> so that when you add a MarkerOptions you add it to your map.

 class MarkerSet extends HashSet<MarkerOptions> { @Override public boolean add(MarkerOptions markerOptions) { boolean didAdd = super.add(markerOptions); if(didAdd) { mMap.addMarker(markerOptions); } return didAdd; } } 

Keep the LatLngBounds object in the activity of your cards. This LatLngBounds object will store boundaries for which you have already requested data from the server.

When moving the camera, the card checks to see if new boundaries are within the currently stored boundaries, if you do not request a server and increase the boundaries, do not request a server.

 mMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() { @Override public void onCameraMove() { LatLngBounds currentBounds = mMap.getProjection().getVisibleRegion().latLngBounds; if (mBounds == null) { mBounds = currentBounds; // Perform server request and get markers passing in currentBounds // Following to be performed in server request callback MarkerOptions markerOptions = new MarkerOptions(); // set marker options here mMarkerSet.add(markerOptions); } else { if (!(mBounds.contains(currentBounds.northeast) || mBounds.contains(currentBounds.southwest))) { mBounds = mBounds.including(currentBounds.northeast); mBounds = mBounds.including(currentBounds.southwest); // Perform server request and get markers passing in currentBounds // Following to be performed in server request callback MarkerOptions markerOptions = new MarkerOptions(); // set marker options here mMarkerSet.add(markerOptions); } } } }); 

Make sure you always call the server request for currentBounds . This algorithm can be improved if you manage to shorten currentBounds when currentBounds and mBounds overlap.

Assumption

Note that here it is assumed that when moving the camera, currentBounds falls slightly from mBounds . Otherwise, new tokens are not loaded. Referring to the image, if the user moves from the visible green area to orange, the mBounds value will be a blue rectangle, and therefore the white area will not be covered. However, in practice, moving the camera horizontally or vertically is not easy, it will cause a call to the server method and new markers for the unloaded area that will be loaded.

How will mBounds be aggregated?

Hope this helps. :)

+1
source

Source: https://habr.com/ru/post/1265443/


All Articles