MonoCross – Part 2

Overview

In Part 1 I outlined how a MonoCross application’s models, controllers, and views work together to provide a cross-platform smartphone solution (it also supports Windows and the web but smartphones reuse is what I’m currently interested in).

The goal now is to create an Android application using Mono for Android and MonoCross that aligns with the meta-functions of navigation and data collection. Using other data collection and navigation prototypes that I’ve worked on as user interface guides, this Android application will consist of screens and a minimal workflow to support transition from screen-to-screen (barebones models and controllers will be created to support the various views).

Designing The Application

This Android application consists of seven screens:

  • MainList – A list of high level functions (Navigate, Collect, Browse, Map, and Status)
  • NavigateList – A list of navigation selections (Map, Waypoint, Coordinate)
  • CollectList – A list of data collection selections (Point, Line, Area)
  • Point – A data collection screen offering sub-screens via a tabbed interface
  • Coordinate – A navigation data entry screen for inputting latitude and longitude
  • Navigate – A navigation screen displaying a custom control
  • Map – A Google Maps display screen

The workflow below shows specific screen-to-screen transitions (tapping “Navigate” will take you to the Navigate screen, tapping Coordinate on that screen will take you to the Coordinate data entry screen, etc.).

Creating The Solution

The development tools I used to create the Android application were:

  • Visual Studio 2010 Ultimate
  • Mono for Android (includes associated Android and Java SDKs)
  • MonoCross
  • MonoCross Project Templates

The first step is to create the application solution. In the New Project dialog (File-New-Project), select MonoCross in the Installed Templates list and then select the MonoCross Android Application template to the right. Clicking OK creates the new solution containing the HB1.MD project. The HB1.MD project will contain the application’s models and controllers.

      

The next step is to add a container to the solution. In the Add New Project dialog (right-click Solution, Add-New Project), select MonoCross in the Installed Templates list and then select the MonoCross Android Container to the right. Clicking OK creates a new container project called HB1.Droid in the solution. The HB1.Droid project will contain the application’s views.

     

A HB1.MD project reference (green) is added to the HB1.Droid container project (yellow) and HB1.Droid is set as the startup project.

Next run the application (Debug-Start Debugging) to start the Android emulator and deploy the application to the emulator to test your work so far.

     

The next step is to create the models, controllers, and views that make up the application.

x Model Controller View
1a MainList MainListController MainListView
1b NavigateList NavigateListController NavigateListView
1c CollectList CollectListController CollectListView
2 Point PointController PointView
3 CoordinateController CoordinateView
4 NavigateController NavigateView
5 MapController MapView

I’ll build the models, controllers, and views in the priority order listed – 1a, 1b, 1c, 2, 3, etcetera.

Building The List Screens

The three list screens – MainList, NavigateList, and CollectList – are simple screens that list the navigational commands that allow the user to perform various application functions. The command items in each list a contained in a list model (one for each screen) and displayed by each list screens controller.

Creating List Models

The Main, Navigate, and Collect list models are simple POCOs (Plain Old CLR Objects) that inherit from generic List<T>.

ListItem

The ListItem POCO is the building block of the other three lists.

MainList

MainList is a generic List<T> of ListItems.

NavigateList

NavigateList is also a generic List<T> of ListItems.

CollectList

And CollectList is also a generic List<T> of ListItems.

Creating List Controllers

The MainList, NavigateList, and CollectList controllers initialize and populate the respective models with data.

MainListController

NavigateListController

CollectListController

Registering the List Controllers

The three controllers are added to the NavigationMap along with their URI-based navigation templates.

Creating List Views

The MainList, NavigateList, and CollectList views are based on the MXListActivityView class. In each case, a string array of items is created by iterating through the specific model and passed to the listview’s adapter for screen display.

MainListView

NavigateListView

CollectListView

Binding List Views to Application

The three list views must be added to the Android container (lines 23-25) so they can be rendered and displayed onscreen.

Here are the three list views rendered independently on application startup (this is done by changing the controller assocatioed with NavigationMap.Add(“”, …) in App.cs).

          

Implementing List Navigation

Navigation from the MainList screen to the NavigateList screen or the CollectList screen is done by overriding the OnListItemClick() method in MainListView.

In this method (which is called when a list item is tapped), we get the DisplayName of the individual list item from the model (line 39) and pass it into the navigation engine (line 40).

The navigation engine uses the NavigationMap to determine which controller to call. If the Navigate item is tapped, the NavigationMap is searched for “Navigate” and, when found, the NavigateListController is instantiated, populating the NavigateList model and displaying the NavigateList view.

Building The Point Screen

Creating Point Model

The model for the Point screen is a simple POCO with a few test properties that we’ll display onscreen.

Creating Point Controller

The Point controller populates the Point model with test data when loaded.

Creating Point View

The design for the Point screen calls for a tabbed user interface. To create a tabbed UI you need to create a tab layout file, a view for each of the tabs, and a view to tie the previous three together.

The tab layout file is an XML that contains the declarative elements that specify the layout for the tabs and tab content. A tab layout file has both a TabHost and a TabWidget. The TabHost is the root node for the layout and contains a TabWidget for displaying the tabs and a FrameLayout for displaying the tab content.

This tab layout field above is referenced in line 27 of the PointView where it is set as the view’s content. We also reference two other views, one for each of the two tabs, when we create new intents and bind them to the TabHost (lines 32-39; lines 41-47).

When rendered onscreen the view will look like this.

In order to display point data onscreen, we need to create a layout file for each tab view and, inside the tab view, populate the layout fields.

Here’s the two files for Tab 1.

     

And what it looks like when rendered onscreen.

And here’s the two files for Tab 2.

     

And what it looks like when it’s rendered onscreen.

Additional information about created tabbed screens in Android can be found here.

“Wiring” Point into Application

In line 23 of App.cs, the “Point” URI is added to the NavigationMap along with its relationship to the PointController.

In line 27 of MainReceiver.cs, PointView is added to the Android container.

And in the CollectList view, the OnListItemClick() method is overriden so the selected line item (in this case “Point”) can be extracted and passed to the navigation engine.

Building The Coordinate Screen

I decided not to create a Coordinate model because it wasn’t necessary to show the transition between the Coordinate and Navigate screens (though one could be created if it was necessary to create coordinates to pass between screens).

Creating Coordinate Controller

Creating Coordinate View

Because we’re going to display some controls on the screen we need to set the content view of the view to a layout file (line 27).

Here’s the layout file that we referencing in line 27.

And here’s what the view looks like when it’s rendered on the emulator.

And on an actual device (the difference in appearance is because device-independent coordinates were not used).

“Wiring” Coordinate into Application

In line 25 of App.cs, the “Coordinate” URI is added to the NavigationMap along with its relationship to the CoordinateController.

In line 29 of MainReceiver.cs, CoordinateView is added to the Android container.

And in the NavigateList view, the OnListItemClick() method is overriden so the selected line item (in this case “Coordinate”) can be extracted and passed to the navigation engine.

Building The Navigate Screen

To create a navigation compass on the Navigate screen we first need to add a reference to OpenTK (yellow), the Android assembly that implements OpenGLES 2.0.

Creating Navigate Controller

Creating Navigate View

The content for the NavigateView is set to a Navigate layout (line 33).

In which we define a PaintingView element (lines 7-11).

Which is an class that inherits from AndroidGameView. In this view we do all of the drawing required.

To render a custom control by drawing directly onto the screen.

Obviously this is just a simple triangle rendered on the screen that doesn’t do anything, but with more time and effort it could be turned into a compass pointer that could give “as the crow flies” directions to a specific coordinate.

“Wiring” Navigate into Application

In line 27 of App.cs, the “StartNavigation” URI is added to the NavigationMap along with its relationship to the NavigateController.

In CoordinateView, a reference to the Go buttion is obtained by using FindViewById<T>. The click event of the Go button is wired to the StartNavigation() method which creates a “StartNavigation” URI and passes it to the navigation engine.

Finally, in line 31 of MainReceiver.cs, NavigateView is added to the Android container.

Building The Map Screen

To display a Google Map onscreen we need to add a reference to Mono.Android.GoogleMaps (yellow) to the container project.

Creating Map Controller

Creating Map View

The MappingView inherits from both Android’s MapActivity and MonoCross’ IMXView. Its content view is set to a MapLayout (line 32) and a reference to the MapView in the layout is obtained by using FindViewById<T> (line 34).

The MapView component in the MapLayout file contains an API key obtained from Google that allows you to access Google Maps.

And display the maps onscreen.

“Wiring” Map into Application

In line 29 of App.cs, the “Map” URI is added to the NavigationMap along with its relationship to the MapController.

In line 33 of MainReceiver.cs, MappingView is added to the Android container.

Conclusions

In 31 hours it was possible to create an “skeleton” Android application using the MonoCross framework and just 536 lines of custom code.

 

This entry was posted in Software Development and tagged , , , . Bookmark the permalink.