Map Perfomance Issue while loading Graphic Overlay in Android Runtime 100.5.0

693
3
09-11-2019 03:40 AM
AsifIsmail
New Contributor III

Hello All,

We are migrating out android app from 10.12 to 100.5.0, though almost 90% is completed. we have encountered a serious performance problem which leads to ANR and getting stuck of map view.

So here is the problem :

We have a rest API (normal json based,not feature layer) which expose an array of geo locations.our requirement is such that we have to call this api whenever the user moves or pans the map and draw the overlay of points (from the api response )in the current visible extent of the map using graphics overlay.

I have tried viewpointchangelistener() on the map view,the problem with that is the callback gets triggered so often,which results in unwanted api calls.also i have read from the document that this is not right place to do long operation.

then i have switched to navigationchangedlistener() and call the api if the map is not currently navigating on the current visible extent, though this has improved the performance considerably, still we have the problem.

here is the code that i use : 

my navigation changed listener : 

_mapView.addNavigationChangedListener(
        navigationChangedEvent -> {
          if (!navigationChangedEvent.isNavigating()) {
            System.out.println("navigating");
            if (_mapView.getMapScale() < 50000) {
              mCurrentEnvelope = _mapView.getVisibleArea().getExtent();
              getBusStopsList();
            }
          }
        });

method which calls the API - getBusStopsList() :

private void getBusStopsList() {
  System.out.println("calling busstops api ");
  Envelope envelope = mCurrentEnvelope;

  mBusRouteManager.getBusStopsList(
      envelope.getXMin(),
      envelope.getYMin(),
      envelope.getXMax(),
      envelope.getYMax(),
      getLanguage(),
      new BusRouteManager.BusStopsListener() {
        @Override
        public void onSuccess(List<Stop> ptStopList) {
          System.out.println("recieved " + ptStopList.size() + " stops");

          if (ptStopList.size() > 0) {
            for (int i = 0; i < ptStopList.size(); i++) {
              busStopHashMap.put(STOP_NAME, ptStopList.get(i).Name);
              busStopHashMap.put(STOP_ID, ptStopList.get(i).Id);
              busStopHashMap.put(STATELESS, ptStopList.get(i).Stateless);
              busStopHashMap.put(STOP_DISPLAY_ID, ptStopList.get(i).DisplayId);
              busStopHashMap.put(LAT, ptStopList.get(i).getLocation().getX());
              busStopHashMap.put(LON, ptStopList.get(i).getLocation().getY());
              busStopHashMap.put(OVERLAY_TYPE, BUS_STOPS_OVERLAY);

              Point graphicPoint =
                      new Point(ptStopList.get(i).getLocation().getX(), 
                                 ptStopList.get(i).getLocation().getY());

              Graphic stopGraphic =
                      new Graphic(
                              graphicPoint,
                              busStopHashMap,
                              busStopSymbol);
              mBusStopsGraphicsOverlay.getGraphics().add(stopGraphic);
            }
          }
        }

        @Override
        public void onFailure(String message) {
          mDisplayUtils.showToast(message, MapActivity.this, Toast.LENGTH_SHORT);
        }
      });
}

This method internally makes a retrofit call to the api and onSuccess loops through the list and add the graphic to the overlay.

also this triggers lot of Garbage collecting activities and the respective logs gets printed in logCat.

when the app gets stuck, because of this issue. i get log saying that its tombstoned

I am sure that the issue is because of this method, when i comment this method from executing everything runs smoothly.

The same methodology was used in 10.2.9 which was working perfectly fine (we have earlier used scalechangedlistener() )

Please suggest some better approach regarding this issue.

0 Kudos
3 Replies
GuntherHeppner
Esri Contributor

Hi Asif,

Is the `getBusStopsList` method synchronous, i.e. blocks while making the retrofit call and adding the graphics to the overlay? If so, could you try to make this an asynchronous call that does the network request and adding the graphics on a background thread?

Gunther

0 Kudos
AsifIsmail
New Contributor III

thanks gunther,

will try that approach and check 

0 Kudos
AsifIsmail
New Contributor III

Hi Gunther,

I have changed the code as per your suggestion, and it looks improved but still i have encountered a crash once during testing.

here is the changed code : 

navigation changed listener : 

_mapView.addNavigationChangedListener(
        navigationChangedEvent -> {
          if (!navigationChangedEvent.isNavigating()) {
            System.out.println("navigating");

            if (_mapView.getMapScale() < 50000) {
              mCurrentEnvelope = _mapView.getVisibleArea().getExtent();
              // getBusStopsList();

              if (mLoadStopsTask != null
                      && !mLoadStopsTask.isCancelled()
                      && mLoadStopsTask.getStatus() != AsyncTask.Status.FINISHED) {
                mLoadStopsTask.cancel(true);
              }
              mLoadStopsTask = new LoadBusStopTask();
              mLoadStopsTask.execute();
            }
          }
        });

Async task which calls getBusStopsList() :

private class LoadBusStopTask extends AsyncTask<Void, Void, Void> {

  @Override
  protected Void doInBackground(Void... voids) {
    getBusStopsList();
    return null;
  }
}

Retrofit call : 

private void getBusStopsList() {
  System.out.println("calling busstops api ");
  Envelope envelope = mCurrentEnvelope;

  mBusRouteManager.getBusStopsList(
      envelope.getXMin(),
      envelope.getYMin(),
      envelope.getXMax(),
      envelope.getYMax(),
      Darb.getLanguage(),
      new BusRouteManager.BusStopsListener() {
        @Override
        public void onSuccess(List<PTStop> ptStopList) {
          System.out.println("recieved " + ptStopList.size() + " stops");


          if (ptStopList.size() > 0) {
            for (int i = 0; i < ptStopList.size(); i++) {
              busStopHashMap.put(STOP_NAME, ptStopList.get(i).Name);
              busStopHashMap.put(STOP_ID, ptStopList.get(i).Id);
              busStopHashMap.put(STATELESS, ptStopList.get(i).Stateless);
              busStopHashMap.put(STOP_DISPLAY_ID, ptStopList.get(i).DisplayId);
              busStopHashMap.put(LAT, ptStopList.get(i).getLocation().getX());
              busStopHashMap.put(LON, ptStopList.get(i).getLocation().getY());
              busStopHashMap.put(OVERLAY_TYPE, BUS_STOPS_OVERLAY);

              Point graphicPoint =
                      new Point(ptStopList.get(i).getLocation().getX(), ptStopList.get(i).getLocation().getY());

              Graphic stopGraphic =
                      new Graphic(
                              graphicPoint,
                              busStopHashMap,
                              busStopSymbol);
              mBusStopsGraphicsOverlay.getGraphics().add(stopGraphic);
            }
          }
        }

        @Override
        public void onFailure(String message) {
          mDisplayUtils.showToast(message, MapActivity.this, Toast.LENGTH_SHORT);
        }
      });
}

please do provide a solution, as we cannot release the app with this bug

we have official license for SDK and Arc Pro products,its also possible for us to request a official help if required..please direct.

0 Kudos