Skip to content

Instantly share code, notes, and snippets.

@brezinajn
Last active September 11, 2020 12:52
Show Gist options
  • Save brezinajn/bdc5044ff942ba74e88ffdf06b9f37d8 to your computer and use it in GitHub Desktop.
Save brezinajn/bdc5044ff942ba74e88ffdf06b9f37d8 to your computer and use it in GitHub Desktop.
import android.content.Context;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.LatLng;
import com.google.maps.android.clustering.ClusterItem;
import com.google.maps.android.collections.MarkerManager;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
// contracts for getting required info out of T
interface LatLngGetter<T>{
LatLng get(T t);
}
interface TitleGetter<T>{
String get(T t);
}
interface SnippetGetter<T>{
String get(T t);
}
// concrete implementation for ClusterItem getters
class ClusterItemLatLngGetter<T extends ClusterItem> implements LatLngGetter<T>{
@Override
public LatLng get(T clusterItem) {
return clusterItem.getPosition();
}
}
class ClusterItemTitleGetter<T extends ClusterItem> implements TitleGetter<T>{
@Override
public String get(T clusterItem) {
return clusterItem.getTitle();
}
}
class ClusterItemSnippetGetter<T extends ClusterItem> implements SnippetGetter<T>{
@Override
public String get(T clusterItem) {
return clusterItem.getSnippet();
}
}
public class ClusterManager<T> implements
GoogleMap.OnCameraIdleListener,
GoogleMap.OnMarkerClickListener,
GoogleMap.OnInfoWindowClickListener {
public ClusterManager(Context context, GoogleMap map, MarkerManager markerManager, LatLngGetter<T> latLngGetter, TitleGetter<T> titleGetter, SnippetGetter<T> snippetGetter) {
// ...
}
public ClusterManager(Context context, GoogleMap map, LatLngGetter<T> latLngGetter, TitleGetter<T> titleGetter, SnippetGetter<T> snippetGetter) {
this(context, map, new MarkerManager(map), latLngGetter, titleGetter, snippetGetter);
}
public static <T extends ClusterItem>ClusterManager<T> factory(Context context, GoogleMap map){
return new ClusterManager<>(
context,
map,
new ClusterItemLatLngGetter<>(),
new ClusterItemTitleGetter<>(),
new ClusterItemSnippetGetter<>()
);
}
public interface OnClusterClickListener<T> {
boolean onClusterClick(Cluster<T> cluster);
}
public interface OnClusterInfoWindowClickListener<T> {
void onClusterInfoWindowClick(Cluster<T> cluster);
}
public interface OnClusterInfoWindowLongClickListener<T> {
void onClusterInfoWindowLongClick(Cluster<T> cluster);
}
public interface OnClusterItemClickListener<T> {
boolean onClusterItemClick(T item);
}
public interface OnClusterItemInfoWindowClickListener<T> {
void onClusterItemInfoWindowClick(T item);
}
public interface OnClusterItemInfoWindowLongClickListener<T> {
void onClusterItemInfoWindowLongClick(T item);
}
}
public class NonHierarchicalDistanceBasedAlgorithm<T> extends AbstractAlgorithm<T> {
NonHierarchicalDistanceBasedAlgorithm(LatLngGetter<T> latLngGetter){
// ...
}
// use the latLngGetter.get(T) to get latLng
// from getClusters method:
// StaticCluster<T> cluster = new StaticCluster<>(latLngGetter.get(candidate.mClusterItem));
// if needed static NonHierarchicalDistanceBasedAlgorithm<T extends ClusterItem> factory() can be provided
// in same manner as with ClusterManager
}
public abstract class AbstractAlgorithm<T> implements Algorithm<T> {
private final ReadWriteLock mLock = new ReentrantReadWriteLock();
@Override
public void lock() {
mLock.writeLock().lock();
}
@Override
public void unlock() {
mLock.writeLock().unlock();
}
}
public interface Algorithm<T> {
boolean addItem(T item);
boolean addItems(Collection<T> items);
void clearItems();
boolean removeItem(T item);
boolean updateItem(T item);
boolean removeItems(Collection<T> items);
Set<? extends Cluster<T>> getClusters(float zoom);
Collection<T> getItems();
void setMaxDistanceBetweenClusteredItems(int maxDistance);
int getMaxDistanceBetweenClusteredItems();
void lock();
void unlock();
}
public class DefaultClusterRenderer<T> implements ClusterRenderer<T>{
public DefaultClusterRenderer(Context context, GoogleMap map, ClusterManager<T> clusterManager, LatLngGetter<T> latLngGetter, TitleGetter<T> titleGetter, SnippetGetter<T> snippetGetter){
// ...
}
// use the latLngGetter.get(T) to get latLng
// use the titleGetter.get(T) to get title
// use the snippetGetter.get(T) to get snippet
}
public interface Cluster<T> {
LatLng getPosition();
Collection<T> getItems();
int getSize();
}
public interface ClusterRenderer<T> {
void onClustersChanged(Set<? extends Cluster<T>> clusters);
void setOnClusterClickListener(ClusterManager.OnClusterClickListener<T> listener);
void setOnClusterInfoWindowClickListener(ClusterManager.OnClusterInfoWindowClickListener<T> listener);
void setOnClusterInfoWindowLongClickListener(ClusterManager.OnClusterInfoWindowLongClickListener<T> listener);
void setOnClusterItemClickListener(ClusterManager.OnClusterItemClickListener<T> listener);
void setOnClusterItemInfoWindowClickListener(ClusterManager.OnClusterItemInfoWindowClickListener<T> listener);
void setOnClusterItemInfoWindowLongClickListener(ClusterManager.OnClusterItemInfoWindowLongClickListener<T> listener);
void setAnimation(boolean animate);
void onAdd();
void onRemove();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment