Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[android] Produce a more visible error when not calling SDK methods from the UiThread #9896

Closed
Guardiola31337 opened this issue Aug 31, 2017 · 7 comments
Labels
Android Mapbox Maps SDK for Android

Comments

@Guardiola31337
Copy link
Contributor

  • @jfirebaugh noticed that there are a significant number of issues caused by not adhering to the @UiThread annotations and calling SDK methods from a background thread.

Because thread annotations are simply Lint checks and do not affect one’s build or compilation @ivovandongen suggested that we can do two things here, depending on how many methods it concerns:

  • Create an annotation processor that inserts actual checks
  • Add some manual checks on key places to verify which thread your code is running on

A compilation-time error would be ideal, but if that's not possible a runtime error would be ok.

cc/ @jfirebaugh @ivovandongen @zugaldia

@Guardiola31337 Guardiola31337 added the Android Mapbox Maps SDK for Android label Aug 31, 2017
@zugaldia
Copy link
Member

zugaldia commented Sep 7, 2017

cc: @tobrun

@LukasPaczos
Copy link
Contributor

To add something to this one - there is no way to add code to an existing Java class via an annotation processor. There was a project called Lombok some time ago, but it looks like it's dead and here is the trick they've used.

Therefore, I think that only

Add some manual checks on key places to verify which thread your code is running on

is applicable here.

Another, more complicated approach, would be to wrap all public methods of a class that we want to "thread-check" with an interface and push through Proxy. For example, in OnMapReadyCallback instead of returning MapboxMap we would return an interface with all the public methods of MapboxMap and then with each method call we would be able to use predefined InvocationHandler:

  private static class MyInvocationHandler implements InvocationHandler {

    private final MapboxMap mapboxMap;

    public MyInvocationHandler(MapboxMap mapboxMap) {
      this.mapboxMap = mapboxMap;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      if (!Looper.myLooper().equals(Looper.getMainLooper())) {
        throw new IllegalThreadStateException();
      }

      return method.invoke(mapboxMap, args);
    }
  }

Above change is probably cleaner but it's a SEMVER change, adds another layer of complication and code would be a bit harder to maintain, so I don't think it's worth it here.

@tobrun
Copy link
Member

tobrun commented Jan 9, 2018

Great analysis @LukasPaczos, one thing that came to mind for the manual approach is that we can guard a lot of the API through the code generation of the template files. This will cover a large part of the API though we still need to manually update components as MapboxMap, MapView, Projection etc.

@LukasPaczos
Copy link
Contributor

Good point @tobrun, but basically everything that's generated is finally pushed through the pipeline of MapboxMap, MapView, Projection... and we don't want to restrict constructors, getters, setters etc. of Layers and Properties to UI Thread only, just the final call pushing it to the map.

It seems like all comes down to updating the methods ourselves.

@tobrun
Copy link
Member

tobrun commented Jan 9, 2018

everything that's generated is finally pushed through the pipeline.. and we don't want to restrict constructors, getters, setters etc.

That is true for most cases but since Layer/Source are peer components, they can execute native code without involving the pipeline. Eg. GeoJSONSource#setGeoJson directly invokes the c++ equivalent hook without any other component involved. So yes, we need to restrict constructors, getters, .. when applicable.

@LukasPaczos
Copy link
Contributor

Oh yes, thanks for emphasizing that @tobrun, I missed it. In this case, adding checks to the code templates will cover a decent chunk of the API.

@jfirebaugh
Copy link
Contributor

#11978

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Android Mapbox Maps SDK for Android
Projects
None yet
Development

No branches or pull requests

5 participants