Skip to content

Instantly share code, notes, and snippets.

@tprochazka
Created May 7, 2012 04:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tprochazka/2625894 to your computer and use it in GitHub Desktop.
Save tprochazka/2625894 to your computer and use it in GitHub Desktop.
/**
* Add WeakReference that refer equals() and hashCode() methods to reference object.
*
* @author Tomáš Procházka &lt;<a href="mailto:tomas.prochazka@atomsoft.cz">tomas.prochazka@atomsoft.cz</a>&gt;
* @version $Revision: 0$ ($Date: 30.11.2011 14:53:06$)
*/
public class BetterWeakReference<T> extends WeakReference<T> {
/**
* Constructs a new weak reference to the given referent. The newly created
* reference is not registered with any reference queue.
*
* @param r the referent to track
*/
public BetterWeakReference(T r) {
super(r);
}
/**
* Constructs a new weak reference to the given referent. The newly created
* reference is registered with the given reference queue.
*
* @param r the referent to track
* @param q the queue to register to the reference object with. A null value
* results in a weak reference that is not associated with any
* queue.
*/
public BetterWeakReference(T r, ReferenceQueue<? super T> q) {
super(r, q);
}
@Override
public boolean equals(Object o) {
if (o instanceof WeakReference<?> && get() != null) {
return get().equals(((WeakReference<?>) o).get());
}
return false;
}
@Override
public int hashCode() {
if (get() != null) {
return get().hashCode();
}
return super.hashCode();
}
}
/**
* Global one way asynchronous notification mechanism between parts of application based on Handler class.
* For example from service to activities.
*
* <p>
* Notification are always delivered to the UI thread.
* </p>
*
* <p>
* This class keep all listeners as weak reference so it is save to add whole activities as listeners, but do not use
* anonymous listeners.
* </p>
*
* <p>
* Reference to this class should be obtained via <code>SL.get(getActivity(), GlobalObserverService.class)</code>
* </p>
*
* <p>
* <b>Usage:</b>
* </p>
*
* <p>
* Register listener:
* <code>SL.get(getActivity(), GlobalObserverService.class).addListener(R.id.message_update_completed, this);</code>
* </p>
* <p>
* Call listener:
* <code>SL.get(getActivity(), GlobalObserverService.class).addListener(R.id.message_update_completed, this);</code>
* </p>
*
* @author Tomáš Procházka &lt;<a href="mailto:tomas.prochazka@atomsoft.cz">tomas.prochazka@atomsoft.cz</a>&gt;
* @version $Revision: 0$ ($Date: 30.11.2011 11:55:53$)
*/
public class GlobalHandlerService implements Callback {
Context mContext;
private Handler mhandler;
private SparseArray<List<BetterWeakReference<Callback>>> mListenersSpecific = new SparseArray<List<BetterWeakReference<Callback>>>();
private List<BetterWeakReference<Callback>> mListenersUniversal = new ArrayList<BetterWeakReference<Callback>>();
public GlobalHandlerService(Context context) {
super();
this.mContext = context;
mhandler = new Handler(Looper.getMainLooper(), this);
}
/**
* @see android.os.Handler#sendMessage(android.os.Message)
*/
public final boolean sendMessage(Message msg) {
return mhandler.sendMessage(msg);
}
/**
* @see android.os.Handler#sendEmptyMessage(int)
*/
public final boolean sendEmptyMessage(int what) {
return mhandler.sendEmptyMessage(what);
}
/**
* @see android.os.Handler#sendEmptyMessageDelayed(int, long)
*/
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
return mhandler.sendEmptyMessageDelayed(what, delayMillis);
}
/**
* @see android.os.Handler#sendEmptyMessageAtTime(int, long)
*/
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
return mhandler.sendEmptyMessageAtTime(what, uptimeMillis);
}
/**
* @see android.os.Handler#sendMessageDelayed(android.os.Message, long)
*/
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
return mhandler.sendMessageDelayed(msg, delayMillis);
}
/**
* @see android.os.Handler#sendMessageAtTime(android.os.Message, long)
*/
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
return mhandler.sendMessageAtTime(msg, uptimeMillis);
}
/**
* @see android.os.Handler#sendMessageAtFrontOfQueue(android.os.Message)
*/
public final boolean sendMessageAtFrontOfQueue(Message msg) {
return mhandler.sendMessageAtFrontOfQueue(msg);
}
/**
* @see android.os.Handler#removeMessages(int)
*/
public final void removeMessages(int what) {
mhandler.removeMessages(what);
}
/**
* @see android.os.Handler#removeMessages(int, java.lang.Object)
*/
public final void removeMessages(int what, Object object) {
mhandler.removeMessages(what, object);
}
public Handler getHandler() {
return mhandler;
}
/**
* Add listener for specific type of message by its {@link Message#what}.
*
* @param what ID of message that will be only notified to listener
* @param listener
*/
public synchronized void addListener(int what, Callback listener) {
List<BetterWeakReference<Callback>> whatListofListeners = mListenersSpecific.get(what);
if (whatListofListeners == null) {
whatListofListeners = new ArrayList<BetterWeakReference<Callback>>();
mListenersSpecific.put(what, whatListofListeners);
}
BetterWeakReference<Callback> r = new BetterWeakReference<Handler.Callback>(listener);
if (!whatListofListeners.contains(r)) {
whatListofListeners.add(r);
}
}
/**
* Add listener for all messages.
*
* @param listener
*/
public synchronized void addListener(Callback listener) {
BetterWeakReference<Callback> r = new BetterWeakReference<Handler.Callback>(listener);
if (!mListenersUniversal.contains(r)) {
mListenersUniversal.add(r);
}
}
/**
* Remove listener for specific type of message by its {@link Message#what}.
*
* @param what The id of the message to stop listening to.
* @param listener The listener to remove.
*/
public synchronized void removeListener(int what, Callback listener) {
List<BetterWeakReference<Callback>> whatListofListeners = mListenersSpecific.get(what);
if (whatListofListeners == null) {
return;
}
BetterWeakReference<Callback> r = new BetterWeakReference<Handler.Callback>(listener);
if (whatListofListeners.contains(r)) {
whatListofListeners.remove(r);
}
}
/*
* (non-Javadoc)
*
* @see android.os.Handler.Callback#handleMessage(android.os.Message)
*/
@Override
public boolean handleMessage(Message msg) {
// proces listeners for specified type of message what
synchronized (mListenersSpecific) {
List<BetterWeakReference<Callback>> whatListofListeners = mListenersSpecific.get(msg.what);
if (whatListofListeners != null) {
handleListeners(whatListofListeners, msg);
if (whatListofListeners.size() == 0) {
mListenersSpecific.remove(msg.what);
}
}
}
// process universal listeners
handleListeners(mListenersUniversal, msg);
return true;
}
private void handleListeners(List<BetterWeakReference<Callback>> whatListofListeners, Message msg) {
synchronized (whatListofListeners) {
for (BetterWeakReference<Callback> ComparableWeakReference : whatListofListeners) {
if (ComparableWeakReference.get() != null) {
ComparableWeakReference.get().handleMessage(msg);
} else {
whatListofListeners.remove(ComparableWeakReference);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment