Correspondence is all about synchronizing data between users, between devices, and now between platforms. Correspondence is running in Mono for Android.
I created a Silverlight application called ThoughtCloud for a demo. Users share thoughts with this collaborative mind mapper. This Android app presents a read-only list of the clouds shared in the Silverlight application. It can be extended to view those clouds and make changes.
User interface updates
Correspondence is built on top of Update Controls, which is responsible for updating the user interface. The Silverlight and Windows Phone versions of Update Controls work with data binding to implement MVVM. But in Android, there is no data binding. Hence, there is no MVVM. Instead, Android uses adapters.
A ListView is the Android equivalent of the Silverlight ListBox. It is attached to a ListAdapter. It works like an ObservableCollection: any item added to the ListAdapter will appear on the ListView. The following code adds the name of each cloud to the adapter.
private void UpdateCloudArray()
{
_cloudArrayAdapter.Clear();
foreach (Cloud cloud in _identity.SharedClouds)
{
Thought centralThought = cloud.CentralThought;
string text = centralThought == null
? "<null>"
: centralThought.Text.Value ?? "<empty>";
_cloudArrayAdapter.Add(text);
}
}
It’s not very smart to clear the whole adapter each time, but this is proof-of-concept code. In a more sophisticated system, it will update items in the adapter in place.
Tracking dependencies
Now we have to make sure that UpdateCloudArray is run whenever it needs to be. That’s where Update Controls comes in. Update Controls observes what your code touches. What your code reads is what it depends upon. This code reads the SharedClouds, which is a query in the factual model.
fact Identity {
key:
string anonymousId;
query:
Cloud* sharedClouds {
Share s : s.recipient = this
Cloud c : s.cloud = c
}
}
It also reads the CentralThought of each cloud, and the Text of each central thought. These are both mutable properties in the factual model. Whenever any of these things changes, Update Controls can tell. The following code hooks it up.
_depCloudArray = new Dependent(UpdateCloudArray);
_depCloudArray.Invalidated += delegate
{
RunOnUiThread(delegate
{
_depCloudArray.OnGet();
});
};
_depCloudArray.OnGet();
The Dependent object keeps track of dependencies. It takes an update method as a constructor parameter. Whenever it needs to update, it calls this method. It depends upon the things that this method reads.
When one of the dependencies changes, the Dependent goes out-of-date. At that moment, the Invalidated event is raised. The delegate above brings the Dependent back up-to-date on the UI thread.
Finally, the Dependent starts its life out-of-date. So we call OnGet() to bring it up-to-date immediately.
Next steps
The above code is more than I’d like to write for each adapter. Instead, I intend to create adapter classes that build dependency tracking right in. This is the process I went through for the Update Controls library for Windows Forms. WPF and Silverlight have data binding hooks, so I didn’t have to individually augment every control for those versions.
The Silverlight version of Thought Cloud uses HTTP long polling to push changes to other users, so your thoughts immediately appear on their machine. On a phone, this is done through push notifications. I haven’t yet written the push notification service for Android. So this code will not automatically reflect changes made online. That is my next milestone. For now, you have to exit and reenter the app.
This Mono version is slow. I’ve written Android apps in Java, and they were not nearly as slow as this. It could just be that I have to do some optimization in Correspondence. Or it could be the extra layers of the Mono .NET runtime. My Faceted Worlds partner Russell and I are in the middle of the Java port. We’ll know soon whether Correspondence can be performant as a native Android library.