Skip to content

Refactor MapEvents listeners, each listener will include an event data property.#718

Merged
pengdev merged 6 commits intomainfrom
peng-refactor-map-listeners
Oct 6, 2021
Merged

Refactor MapEvents listeners, each listener will include an event data property.#718
pengdev merged 6 commits intomainfrom
peng-refactor-map-listeners

Conversation

@pengdev
Copy link
Copy Markdown
Member

@pengdev pengdev commented Oct 5, 2021

PRs must be submitted under the terms of our Contributor License Agreement CLA.
Fixes: < Link to related issues that will be fixed by this pull request, if they exist >

Pull request checklist:

  • Briefly describe the changes in this PR.
  • Include before/after visuals or gifs if this PR includes visual changes.
  • Write tests for all new functionality. If tests were not written, please explain why.
  • Optimize code for java consumption (@JvmOverloads, @file:JvmName, etc).
  • Add example if relevant.
  • Document any changes to public APIs.
  • Apply changelog label ('breaking change', 'bug 🪲', 'build', 'docs', 'feature 🍏', 'performance ⚡', 'testing 💯') or use the label 'skip changelog'
  • Add an entry inside this element for inclusion in the mapbox-maps-android changelog: <changelog>Refactor MapEvents listeners, so that each listener will include one event data property.</changelog>.

Summary of changes

This PR refactors the MapEventListeners, so that each listener will include one event data property. This unblocks us to add properties to the event data incrementally without breaking our public API.

List of affected listeners:

  • OnCameraChangeListener
  • OnMapIdleListener
  • OnMapLoadedListener
  • OnMapLoadErrorListener
  • OnRenderFrameFinishedListener
  • OnRenderFrameStartedListener
  • OnSourceAddedListener
  • OnSourceDataLoadedListener
  • OnSourceRemovedListener
  • OnStyleDataLoadedListener
  • OnStyleImageMissingListener
  • OnStyleImageUnusedListener
  • OnStyleLoadedListener

This PR also refactors the package name for Map event's data models to com.mapbox.maps.extension.observable inside the sdk-base module, so it can be reused across different plugins.

And fixed the type of TileID's z/x/y properties.

User impact (optional)

@pengdev pengdev requested review from a team and tobrun October 5, 2021 15:30
@kiryldz
Copy link
Copy Markdown
Contributor

kiryldz commented Oct 5, 2021

overall LGTM but let's first fix all CI issues

@pengdev pengdev force-pushed the peng-refactor-map-listeners branch from d516c57 to 232f02d Compare October 5, 2021 17:01
@pengdev pengdev force-pushed the peng-refactor-map-listeners branch from 232f02d to ac8c4a7 Compare October 5, 2021 17:35
@pengdev pengdev force-pushed the peng-refactor-map-listeners branch from cdb09b6 to 5cc1434 Compare October 5, 2021 19:14
@pengdev pengdev changed the title Refactor MapEvents listeners, each listener will include 1 event data property. Refactor MapEvents listeners, each listener will include an event data property. Oct 5, 2021
@pengdev pengdev marked this pull request as ready for review October 5, 2021 19:46
@pengdev pengdev requested review from a team and alexshalamov October 5, 2021 19:46
import com.mapbox.maps.extension.observable.eventdata.ResourceEventData

private val gson by lazy {
Gson()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optimization!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

however could it technically happen that user is parsing several instances of event data from multiple threads? guess it's too advanced though 😄 so let's keep as is

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Gson 's api doc

Gson is typically used by first constructing a Gson instance and then invoking toJson(Object) or fromJson(String, Class) methods on it. Gson instances are Thread-safe so you can reuse them freely across multiple threads.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about koltin serialization?
maybe not in this PR

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about koltin serialization? maybe not in this PR

we were using gson library to serialise/deserialise in our codebase, it would be good to evaluate and replace it across the codebase in a separate PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the gson part mostly stems from our "java" days. Kotlin serialisation would be a good thing to evaluate, additionally a geojson rewrite in kotlin ;)

Copy link
Copy Markdown
Contributor

@kiryldz kiryldz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pengdev LGTM 💎

fun Event.getResourceEventData(): ResourceEventData {
val json = data.toJson()
return Gson().fromJson(json, ResourceEventData::class.java)
return gson.fromJson(json, ResourceEventData::class.java)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add try-catch block?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imho if the data format has been changed, it should be a bug and should throw exceptions so that we can fix it in a patch.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, but is it proper behavior for users? is it possible that our users (developers) can release some app in play market and got crash in app?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you suggest we return nullable EventData instead? If it's a bug inside our code, we could provide non-breaking patch releases to fix it. And so far this has been the default behaviour and no bug report on it yet 🙂

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can discuss it with the team. probably leave as is for now. but let's think about it

several options for now:

  • return nullable
  • support some default value and work with it somehow

also we can send telemetry event for such crashes

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, let's make it as a follow up 👍

Copy link
Copy Markdown
Member

@tobrun tobrun Oct 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, but is it proper behavior for users? is it possible that our users (developers) can release some app in play market and got crash in app?

That statement could be true for every line of code we ship. The program is expected to return this non null data in that specific format, it's part of the contract that gl-native makes with us. Overall, I'm personally leaning more towards a crash-fast approach, we catch issues during development, else they can become unnoticed and broken if not properly exercised. Additionally requiring developers to handle null adds logical branching to their code. This makes it more complex to handle, while it's not expected program output.

import com.mapbox.maps.extension.observable.eventdata.ResourceEventData

private val gson by lazy {
Gson()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about koltin serialization?
maybe not in this PR

* @return a parsed MapLoadedEventData object.
*/
fun Event.getMapLoadedEventData(): MapLoadedEventData {
val json = data.toJson()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pengdev, in a following releases, if native team would provide a formal spec for events, we could auto-generate MapLoadedEventData and remove gson conversion, right? Modification of an internal logic would be a non-breaking change?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could generate the MapLoadedEventData using the formal spec, but I think we still need to deserialise it using gson or koltin serialization

Modification of an internal logic would be a non-breaking change?

Addition of properties inside MapLoadedEventData shouldn't be a breaking change, however, we should not remove or modify the existing properties.

@pengdev pengdev merged commit e56a3f7 into main Oct 6, 2021
@pengdev pengdev deleted the peng-refactor-map-listeners branch October 6, 2021 09:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants