Using Java 1.6 on Android API 13 (3.2):
We are working on a View Model framework. In this framework we can wait on another property to have a value before executing. In the following example we are awaiting the value from ModuleViewProperty before attempting to fetch a data count.
However, we are having an issue where the getModuleView is returning null, after the await has determined it to have a value.
At first glance this appears to be an issue with the ViewModel's property changed framework. However, we are leaning away from that as this issue is not repeatable, as 99 out of 100 times it runs without issue. We're concerned that garbage collection is running in between execution of both anonymous classes, causing unexpected behavior.
Are there any gotchas in how anonymous classes capture variables?
...
protected void RefreshDataCount()
{
awaitValuesFor(ModuleViewProperty).Then(new IAction()
{
@Override
public void Do()
{
if (_fetchCount != null)
_fetchCount.cancel(true);
_fetchCount = new RESTTask<Integer>(_contextProvider.get())
{
@Override
protected RESTCallResult<Integer> Get() throws Exception
{
int viewAutoNumber = getModuleView().AutoNumber;
return _dataProvider.GetCount(getModuleID(), getDataURL(), getFilterKeyID(), viewAutoNumber, getSearchText());
}
@Override
protected void resultReceived(FetchTaskResult<RESTCallResult<Integer>> result)
{
UpdateLoading();
...
setDataCount(result.Value.Content);
}
};
_fetchCount.execute();
UpdateLoading();
}
});
}
...
And so you can see how ModuleViewProperty and getModuleView correlate:
public final static PropertyDef<ModuleView> ModuleViewProperty = new PropertyDef<ModuleView>("ModuleView");
public ModuleView getModuleView()
{
return retrievePropertyValue(ModuleViewProperty);
}
public void setModuleView(ModuleView value)
{
storePropertyValue(ModuleViewProperty, value);
}
And to preempt requests to see awaitValuesFor:
public PropertyAwaiter awaitValuesFor(PropertyDef... dependencies)
{
return new PropertyAwaiter(this, dependencies);
}
And Property Awaiter:
public class PropertyAwaiter
{
private IAction _action;
private List<PropertyDef> _properties;
private ViewModel _viewModel;
public PropertyAwaiter(ViewModel viewModel, PropertyDef... dependencies)
{
_viewModel = viewModel;
_properties = new LinkedList<PropertyDef>(Arrays.asList(dependencies));
}
public void Then(IAction action)
{
if (action == null)
return;
_action = action;
for (final PropertyDef dep : new ArrayList<PropertyDef>(_properties))
{
_viewModel.awaitValueThen(dep, new IAction()
{
@Override
public void Do()
{
_properties.remove(dep);
if (_properties.size() == 0)
_action.Do();
}
});
}
}
}
public <T extends Serializable> void awaitValueThen(final PropertyDef<T> prop, final IAction execute)
{
if (execute == null)
return;
if (runPropertyGetter(prop) == null)
{
PropertyChangedListener<T> changedHandler = new PropertyChangedListener<T>()
{
@Override
public void boundValueChanged(PropertyDef<T> property, T newValue)
{
if (newValue == null)
return;
execute.Do();
removePropertyChangedHandler(prop, this);
}
};
addPropertyChangedHandler(prop, changedHandler);
}
else
{
execute.Do();
}
}
Thanks in advance,
Trey