Click here to Skip to main content
15,889,862 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
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?


Java
...

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:

Java
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:


Java
public PropertyAwaiter awaitValuesFor(PropertyDef... dependencies)
{
	return new PropertyAwaiter(this, dependencies);

}


And Property Awaiter:

Java
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();
				}
			});
		}
	}
}


Java
public <T extends Serializable> void awaitValueThen(final PropertyDef<T> prop, final IAction execute)
{
	if (execute == null)
		return;

	// If we don't have a value, we want to know when the value changes
	if (runPropertyGetter(prop) == null)
	{
		// Wire up to be notified when this property changes
		PropertyChangedListener<T> changedHandler = new PropertyChangedListener<T>()
		{
			@Override
			public void boundValueChanged(PropertyDef<T> property, T newValue)
			{
				// if the new value is not null then we can consider condition met and notify the awaiter
				if (newValue == null)
					return;

				execute.Do();

				// Unwire self as a property changed handler, as the condition was met and we don't need to listen anymore
				removePropertyChangedHandler(prop, this);
			}
		};

		addPropertyChangedHandler(prop, changedHandler);
	}
	else
	{
		// We already have a value and can go ahead and notify the awaiter
		execute.Do();
	}
}



Thanks in advance,
Trey
Posted

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900