Youth Homelessness Survey App with Xamarin.Forms and HockeyApp

Views:  31,189

The Connecticut Coalition to End Homelessness recently concluded the 2017 PIT survey, which is a one-day unduplicated count of sheltered and unsheltered homeless individuals and families across the United States. In addition to the nationwide PIT survey, CCEH conducted a specialized survey to collect data about homeless youth (ages 13 to 25). We partnered with them to develop a mobile application for volunteers to use to collect survey data.

Requirements

The app had to be available for both iOS (6.1 and up) and Android (4.1 and up) users, and support for Windows 10 mobile devices was a nice-to-have. The app needed to provide an authentication mechanism for volunteers, but also allow anonymous surveys to be collected for volunteers who did not wish to, or were not able to authenticate. The app would display a series of multiple choice questions. In some cases, multiple answers were allowed. Also for some questions, the survey required additional information after an answer was chosen (e.g., “if selected, why?”).

Xamarin.Forms

Since it was anticipated that the UI would be consistent across iOS, Android, and Windows, and there were no complex features that would require low-level access to platform-specific APIs, Xamarin.Forms was an adequate option for building the mobile app. The team of developers was already comfortable working in the .NET ecosystem with Visual Studio as an IDE, C# as the programming language, and MVVM as a design pattern. Other frameworks such as Cordova or React Native may have worked fine as well, but the team’s core skills favored Xamarin. There was also already an Azure App Service for managing survey questions and storing survey responses, and the Azure Mobile Client SDK for .NET is available for Xamarin.iOS, Xamarin.Android, and many other .NET flavors. Using this package would allow for maximum code reuse of native business logic for authenticating against the service and making service requests.

Anticipating that there might be small variations between the three operating systems that we would need to account for, we chose to go with a Xamarin.Forms shared project. Because of the team’s familiarity with XAML and MVVM, we chose a Xamarin.Forms XAML shared project.

Screenshot of Xamarin.Forms shared project template in Visual Studio

There are many reasons for choosing one of these templates over another; each has its strengths, and none of the templates limit you as to the kind of app or architecture you can produce.

A XAML app, when developed using MVVM and data binding, can produce a clean separation of UI from app logic, and is particularly useful when you’re building view models to be shared across different UI implementations (e.g., if you were building an app for Xamarin.iOS and Xamarin.Android).

The shared project approach versus the portable approach has its tradeoffs as well. Typically, while developing a cross-platform application, you are focused on testing it on a single platform at a time. If you are actively developing a shared project and focused on testing it on, say, Android, there are no guarantees that the changes you have made will also compile and work for iOS and Windows. A Xamarin.Forms portable project, however, provides much stronger guarantees that when an app compiles for one platform, it will also compile for the other platforms, as well. On the other hand, these guarantees come at a cost, as you have to use patterns like DependencyService, instead of using preprocessor directives (i.e., #ifs) to introduce platform-specific behaviors.

We didn’t actually use text-to-speech in the homelessness survey app; the code above is just a demonstration of shared versus portable design patterns.

Building the app

For the most part, the app development was straightforward, as anticipated. There were a few interesting challenges with solutions, however, that are worth noting.

Multi-select lists

As stated previously, the survey questions were multiple choice, with some questions allowing multiple answers. As of Xamarin.Forms v2.3.3, the core ListView does not support multi-select. In addition to multi-select, we also landed on a UX that would conditionally pop up a text entry underneath a selected answer when more information was necessary, which meant that, depending on the state of the app, the list view rows were not guaranteed to be of equal height. We evaluated two approaches for implementing multi-select, a ListView with Switch and a StackLayout with Buttons.

ListView item template with Switch

With a list of items or an IEnumerable, the first approach to consider is data binding with an item template and items source on a ListView. Since the ListView does not support multi-select, we had to provide a UX that would allow the users to select and unselect answers, and easily see which answers were currently selected. The Switch component provided a reasonable UX for this scenario. When a list item is selected, it toggles the switch component. Likewise, hitting the switch directly toggles it as well. The code sample below shows the ViewCell template implementation that was used. The WrappedAnswerViewModel is a simple view model wrapper around the survey answer model with bindable properties. One of these properties, IsSpecifiable, is a composite property that checks if the answer requires additional input, and if the answer has been selected. A binding to the IsSpecifiable property is used to set the IsVisible property for the Entry text box. Note that the code sample uses an imperative declaration of the item template, but it could have also been declared using XAML.

Here’s how the ListView was instantiated with the DataSource and ItemTemplate.

Here’s a screenshot of a survey question using this ListView approach:

Screenshot of WeCount with ListView-based survey questionThere were two primary issues with this approach from a UX perspective. The first is that list items, once selected, cannot be reselected. So, to toggle a switch for a selected list item, the switch has to be toggled directly. The second issue is that the code above displays a switch component even for questions that only allow a single answer. The first issue could potentially be overcome by nulling out the selected item after toggling the switch. The second issue could potentially be overcome by binding the visibility of the switch to a property signaling single versus multiple selection answers.

Scroll bar visibility

One other minor concern with the ListView approach was whether the volunteer asking the survey questions would see all the answers before moving on to the next question. The integrity of the survey responses was of highest priority, so it was not acceptable for the answers to be potentially biased towards the options that are immediately visible on the screen. By default the Xamarin.Forms ListView fades the scroll bar after a short time period on iOS, Android, and Windows. The stakeholders requested that, if we were to use the ListView approach, the scroll bar be visible all the time. Scroll bar visibility is not part of the ListView API on Xamarin.Forms. However, many Xamarin.Forms controls have a custom renderer class that can be used to customize how the view is rendered on each platform. For example, here is how we disabled scroll bar fading on Android.

After that, we simply had to create a derived class of ListView called SurveyAnswerListView (we didn’t want the renderer to be applied to all ListView instances, just the ones for the survey answers) and use that in the survey page instead of a basic ListView.

StackLayout with Button approach

Although there was a workaround to ensure the scroll bar was always visible, the stakeholders generally felt it would be best to have the Next and Previous question buttons after all answers, to ensure the volunteer had an opportunity to see all answers before moving on. Since the ListView is primarily designed to expand to fit the amount of screen real estate left over, it was no longer the best choice to accommodate the desired UX.

With the ListView approach, the Next and Previous buttons were fixed at the bottom of the screen, as in the following diagram.

Mock-up diagram of ListView approach for CCEH app

The desired UX, however, was more like the following.

Mock-up diagram of StackPanel approach for CCEH app

We created a custom view for each individual answer item, then organized each of these answers into a stack panel.

We placed the Next and Previous buttons at the end of the stack panel, which produced the desired UX.

Screenshot of WeCount with StackPanel-based survey question

Content button for iOS and Windows

One issue with the custom view approach above was that the Xamarin.Forms Button component does not wrap the Button text for iOS and Windows.

To overcome this, we created a custom Button component, ContentButton, which could turn an arbitrary view into a button. We used a Label as the button control, which has text wrapping enabled by default.

We then created an alternate answer view class for iOS and Windows.

Since we used a shared project, adding logic to conditionally use the TextWrappingSurveyAnswerItemView instead of the SurveyAnswerItemView used on Android was easy.

Capturing Metrics with HockeyApp

It was important to the stakeholders to get an idea of what features users were leveraging in the app and where exceptions were occurring. HockeyApp provides an event and metrics tracking API for capturing exactly this kind of information.

We created a simple interface for tracking metrics cross-platform:

We then implemented this interface for all three platforms we were developing for:

You’ll notice that we actually used the DependencyService pattern here, even though we were using the shared project approach. This was purely for convenience, as metrics can become quite pervasive, and the code came out much cleaner without preprocessor directives sprinkled everywhere we needed to capture a metric.

Another piece of code we added was a simple struct for tracking latency metrics for asynchronous operations like network requests. We used a struct to minimize GC impact, and leveraged the IDisposable pattern, which is convenient for these kinds of try/finally operations.

Here’s a snapshot of some of the metrics we were able to capture with HockeyApp.

HockeyApp metrics dashboard from CCEH PITC survey

Azure Mobile Service Client SDK

We used the Azure Mobile Service Client for making requests against the Azure App Service backend, and to authenticate with Google and Microsoft login.

We used the MobileServiceClient.InvokeApiAsync API to access each of the backend REST APIs. This automatically adds authentication token headers to your requests if you’ve authenticated with the MobileServiceClient.LoginAsync API.

Authentication with the MobileServiceClient is platform-specific, so we used a DependencyService pattern similar to the metrics management approach above. The approach is described quite well in the Azure Mobile Service docs.

Deployment with HockeyApp

Since we were on a tight deadline, we used HockeyApp for ad hoc deployment of an app beta for all the volunteers to use during a live survey. Check out the HockeyApp website for more information on how to distribute app ad hoc betas.

Results and Open Source

We completed the client app in about two weeks, just in time to start training volunteers for the youth homelessness survey. The app was used by 200 volunteers on iOS and Android, who together collected more than 1,100 surveys over the span of a few days, with no major outages or issues.

The app and backend service is open source to enable other organizations to adapt and apply the app for their own surveys. The MVVM pattern used should allow for easy reuse in any Xamarin.Forms app.

Leave a Reply

Your email address will not be published. Required fields are marked *