From d2fb1d803a6eebf12f9604cca2b19d69db4826bd Mon Sep 17 00:00:00 2001 From: Alexander Marchuk Date: Thu, 3 Dec 2015 12:00:41 +0300 Subject: [PATCH] [android] add: `Registrator` pattern for listeners. --- .../src/com/mapswithme/util/Listeners.java | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 android/src/com/mapswithme/util/Listeners.java diff --git a/android/src/com/mapswithme/util/Listeners.java b/android/src/com/mapswithme/util/Listeners.java new file mode 100644 index 0000000000..e65c63e751 --- /dev/null +++ b/android/src/com/mapswithme/util/Listeners.java @@ -0,0 +1,94 @@ +package com.mapswithme.util; + +import android.support.annotation.NonNull; + +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * `Registrator` pattern implementation which allows to maintain the list of listeners, + * offers safe adding/removing of listeners during iteration. + *
{@link #finishIterate()} must be called after iteration is complete. + */ +public final class Listeners implements Iterable +{ + private final Set mListeners = new LinkedHashSet<>(); + private final Set mListenersToAdd = new LinkedHashSet<>(); + private final Set mListenersToRemove = new LinkedHashSet<>(); + + private boolean mIterating; + + @Override + public @NonNull Iterator iterator() + { + if (mIterating) + throw new RuntimeException("finishIterate() must be called before new iteration"); + + mIterating = true; + return mListeners.iterator(); + } + + /** + * Completes listeners iteration. Must be called after iteration is done. + */ + public void finishIterate() + { + if (!mListenersToRemove.isEmpty()) + mListeners.removeAll(mListenersToRemove); + + if (!mListenersToAdd.isEmpty()) + mListeners.addAll(mListenersToAdd); + + mListenersToAdd.clear(); + mListenersToRemove.clear(); + mIterating = false; + } + + /** + * Safely registers new listener. If registered during iteration, new listener will NOT be called before current iteration is complete. + */ + public void register(T listener) + { + if (mIterating) + { + mListenersToRemove.remove(listener); + if (!mListeners.contains(listener)) + mListenersToAdd.add(listener); + } + else + mListeners.add(listener); + } + + /** + * Safely unregisters listener. If unregistered during iteration, old listener WILL be called in the current iteration. + */ + public void unregister(T listener) + { + if (mIterating) + { + mListenersToAdd.remove(listener); + if (mListeners.contains(listener)) + mListenersToRemove.add(listener); + } + else + mListeners.remove(listener); + } + + public int getSize() + { + int res = mListeners.size(); + if (mIterating) + { + res += mListenersToAdd.size(); + res -= mListenersToRemove.size(); + } + + return res; + } + + public boolean isEmpty() + { + return (getSize() <= 0); + } +}