-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat: Add overridable shouldRender() method for use case of rendering when cluster doesn't change #996
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
* Restore CustomMarkerClusteringDemoActivity, add ZoomClusteringDemoActivity
library/src/main/java/com/google/maps/android/clustering/view/DefaultClusterRenderer.java
Outdated
Show resolved
Hide resolved
| * method is primarily for optimization of performance, and the default implementation simply | ||
| * checks if the new clusters are equal to the old clusters, and if so, it returns false. | ||
| */ | ||
| protected boolean shouldRender(@NonNull Set<? extends Cluster<T>> oldClusters, @NonNull Set<? extends Cluster<T>> newClusters) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the sets provided here immutable to ensure no additions/removals are made while this method is invoked?
Also, should this method be defined in ClusterRenderer? Exposing an API like that could be generally useful, although I'm not use if custom cluster renderers apart from DefaultClusterRenderer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the sets provided here immutable to ensure no additions/removals are made while this method is invoked?
Good catch - no, and this also made be realize that oldClusters could be null. newClusters can't be null in the current implementations of the clustering algorithms in the library, but given that the renderer can be used with 3rd party implementations of Algorithm we need to protect against that too.
I've fixed this for both parameters to either wrap the set in Collections.unmodifiableSet() if it's not null or pass in an empty set if it is - see f61c81b.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, should this method be defined in ClusterRenderer? Exposing an API like that could be generally useful, although I'm not use if custom cluster renderers apart from DefaultClusterRenderer.
Hmmm, good question. I could see it being useful, both for shouldRender() and shouldRenderAsCluster(). We currently only have DefaultClusterRenderer in the library but there could be 3rd party ones.
The main downside I see is that it's a breaking change for any existing 3rd party implementations of ClusterRenderer as it would require them to implement the method before builds would succeed.
Should we add both shouldRender() and shouldRenderAsCluster() to the ClusterRenderer interface in this PR to group the changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's just keep note of this in case it comes up in the future for a 3rd party implementation of ClusterRenderer—I'm just not sure if it's worth going through the trouble of exposing this feature at the interface level and breaking usages as you mentioned. There's ways to avoid a breaking change (like creating another interface) but again, not sure if it's worth the trouble.
…DefaultClusterRenderer.java Co-authored-by: Chris Arriola <carriola@google.com>
arriolac
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
![]()
|
🎉 This PR is included in version 2.3.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
In the current version of
DefaultClusterRenderer, there is a built-in optimization to avoid re-rendering items when there isn't a change in the clusters.However, as discussed in #774, this prevents use cases where the clusters/markers should be re-rendered even if the cluster contents don't change.
For example, if you want a single item to render as a cluster above a certain zoom level and as a marker below a certain zoom level, this isn't possible - the item will never be updated from the cluster to the marker because that rendering pass is skipped (because the cluster contents didn't change).
This PR adds a new
DefaultClusterRenderer.shouldRender()method that apps can override to control this optimization when necessary. This allows the above use case as the app can track the previous and current zoom levels and force the render to occur when the transition over the zoom threshold is made.A new demo activity
ZoomClusteringDemoActivity(shown as "Clustering: Force on Zoom" in the demo app UI) (gms and v3 flavors) is added as part of this PR to clearly illustrate howshouldRender()is used. This demo also illustrates what I believe is an undocumented feature of the library, which is that theClusterManagerwill call theonCameraIdle()implementation of anyRendererthat implementsGoogleMap.OnCameraIdleListenerbefore clustering and rendering takes place. This allows us to capture the zoom level that can then be used inshouldRender().This feature is backwards-compatible, as the current behavior of apps will not change - the default implementation of
shouldRender()is the same as the current version of the library.Note that the new
ZoomClusteringDemoActivitywon't build when using the existing published library as a dependency becauseshouldRender()doesn't exist in that version of the library (I tested usinggmsImplementation project(':library')as the dependency), so the CI on this PR will fail. Not sure how you want to handle that?Before submitting your PR, there are a few things you can do to make sure it goes smoothly:
BREAKING CHANGEfooter so when this change is integrated a major version update is triggered. See: https://www.conventionalcommits.org/en/v1.0.0/Closes #774 🦕