I am working on adding support for property observations for my open source library droidQuery, however the propertyChange
method is not being called in my tests. What do I need to do to get this to work? Here is my code:
ViewObserver.java
package self.philbrown.droidQuery;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import android.view.View;
/**
* Provides Property Change Listening to simulate bindings
* @author Phil Brown
*
*/
public class ViewObserver implements PropertyChangeListener
{
/** The function to call when the interface's method is invoked. */
private Function function;
/**
* Constructor
* @param droidQuery an instance of droidQuery
* @param function the function to call when the value changes. Will include a {@link Observation}
* Object with information about the KVO operation.
*/
public ViewObserver(Function function)
{
this.function = function;
}
@Override
public void propertyChange(PropertyChangeEvent event) //<-- This is never reached!
{
Observation observation = new Observation(event);
function.invoke($.with((View) event.getSource()), observation);
}
/**
* Represents an observation event that occured.
*/
public static class Observation
{
/** The old value prior the this Observation */
public Object oldValue;
/** The new value */
public Object newValue;
/** The name of the property that has changed from {@code oldValue} to {@code newValue}. */
public String property;
/**
* Constructor. Private since it is only used locally.
* @param event
*/
private Observation(PropertyChangeEvent event)
{
oldValue = event.getOldValue();
newValue = event.getNewValue();
property = event.getPropertyName();
}
}
}
Relevant portions of droidQuery.java (the rest available on github):
/** Used for Property Change Listening to simulate KVO Binding in droidQuery */
private static Map<View, Map<String, WeakReference<Observer>>> observers;
//The constructor has this:
//if (observers == null)
// observers = new HashMap<View, Map<String, WeakReference<Observer>>>();
/**
* Observe changes to the given property and respond to modification events. This requires
* a getter and setter method for the given property on the selected views. Passing "*" will
* add the property observer for all of the fields in each selected view. For example:
* <pre>
* $.with(myButton).observe("selected", new Function() {
* @Override
* public void invoke($ droidQuery, Object... params) {
* Observation ob = (Observation) params[0];
* Log.i("$", ob.property + " changed to " + ob.newValue);
* }
* });
* </pre>
* @param property name of the property to observe. If set to "*", all fields will be observed.
* @param onPropertyChanged the Function to call when the given property has changed. The argument
* passed to {@code onPropertyChanged} will be an instance of {@link ViewObserver.Observation},
* and will contain the old value, new value, and the property name. The given instance of droidQuery
* will have the observing view selected.
*/
public $ observe(String property, Function onPropertyChanged)
{
for (View view : views)
{
Map<String, WeakReference<Observer>> kvo = observers.get(view);
if (kvo == null)
{
kvo = new HashMap<String, WeakReference<Observer>>();
}
WeakReference<Observer> ref = kvo.get(property);
if (ref != null && ref.get() != null)
{
if (property.equals("*"))
ref.get().support.removePropertyChangeListener(ref.get().kvo);
else
ref.get().support.removePropertyChangeListener(property, ref.get().kvo);
}
Observer observer = new Observer();
observer.support = new PropertyChangeSupport(view);
observer.kvo = new ViewObserver(onPropertyChanged);
ref = new WeakReference<Observer>(observer);
if (property.equals("*"))
observer.support.addPropertyChangeListener(observer.kvo);
else
observer.support.addPropertyChangeListener(property, observer.kvo);
kvo.put(property, ref);
observers.put(view, kvo);
}
return this;
}
/**
* Contains Objects pertaining to the property change listener for a view in droidQuery.
*/
public static class Observer
{
/** Manages property observers registered to receive events */
public PropertyChangeSupport support;
/** The property observer */
public ViewObserver kvo;
}