1

I'm trying to instantiate a MapBox map inside an Android Service because I need to stream a navigation routing with my app in background.

Right now I created a Service that when started run an Hander on the main looper, and from there, if my map isn't instantiated yet, I inflate a layout (before I tried to create it by hand, but nothing changed), find the MapView, and fire the getMapASync in order to obtain the MapboxMap object.

It all works, but getMapAsync callback never gets called

Here is a sample code I used

public class MapBoxHandlerService extends Service {
    private final static String TAG = "MapBoxHandlerService";
    private ServiceHandler mServiceHandler;

    static MapBoxHandlerService instance;

    MapView mapView;
    MapboxMap map;

    private final static class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) { super(looper); }

        @Override
        public void handleMessage(final Message msg) {
            currentStartId = msg.arg1;

            final Intent intent = (Intent) msg.obj;
            if (intent==null)
                return;

            if (instance.mapView==null) {
                LayoutInflater inflater = LayoutInflater.from(instance.getApplicationContext());
                View layoutView = inflater.inflate(R.layout.mapbox_layout, null);

                instance.mapView = layoutView.findViewById(R.id.mapView);
                instance.mapView.onCreate(null);
                instance.mapView.addOnDidFailLoadingMapListener((String errorMessage)->{
                    Logger.e(instance.getApplicationContext(),TAG,errorMessage);
                });
                instance.mapView.addOnDidFinishLoadingMapListener(()->{
                    Logger.i(instance.getApplicationContext(),TAG,"map loaded");
                });
                instance.mapView.addOnWillStartLoadingMapListener(()->{
                    Logger.i(instance.getApplicationContext(),TAG,"start map loading");
                });
                instance.mapView.addOnWillStartRenderingMapListener(()->{
                    Logger.i(instance.getApplicationContext(),TAG,"start map rendering");
                });
                instance.mapView.getMapAsync((@NonNull MapboxMap mapboxMap) -> {
                    instance.map = mapboxMap;

                    instance.map.setStyle(Style.MAPBOX_STREETS, (Style loadedMapStyle) -> {
                        LocationComponent locationComponent = instance.map.getLocationComponent();
                        locationComponent.setCameraMode(CameraMode.TRACKING_GPS);
                        locationComponent.setRenderMode(RenderMode.GPS);
                    });
                });
                instance.mapView.onStart();
                instance.mapView.invalidate();
            }
        }
    }

    @Override
    public void onCreate() {
        mServiceHandler = new ServiceHandler(Looper.getMainLooper());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        instance=this;

        Message msg = mServiceHandler.obtainMessage();
        msg.obj=intent;
        msg.arg1=startId;
        msg.arg2=0;
        mServiceHandler.sendMessage(msg);
        startForeground(9, Utils.createServiceNotification(this, "MapBox service",getResources().getString(R.string.service_active)));

        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) { return null; }
}

and when this service is started, I already called Mapbox.getInstance(getApplicationContext(), MapBoxAccessToken) outside the service (in the App onCreate)

Any idea on what's wrong with this code?

supergoofy
  • 21
  • 4

1 Answers1

1

I figured out myself what was the problem: I forgot to add my layout to the WindowManager service and I needed to set the MapView TextureMode attribute.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
supergoofy
  • 21
  • 4