Having the opportunity to work with android wearables, particularly smart watches, is very exciting as this is getting more popular nowadays. Building mobile and wearable device apps is not as complex as you may think. I admit that at first I was kind of afraid when I was assigned to explore and build apps for mobile and wearable, but using the right tools and technologies makes life easier for me to build those apps and prototypes.
Ermm.. right tools?
Yes, and I was referring to the awesome Xamarin. Xamarin allows you to build cross-platform apps for Android, iOS and Windows and it uses C# as the backend language. They also introduced Xamarin Forms which allows you to easily create native UI layouts that can be shared across Android, iOS, and Windows Phone. For as long as you know C# then creating the logic for your app is easy because you are already familiar with the syntax and most of all the .NET libraries. The only learning curve that you will need to take when transitioning from web to mobile is that you will need to know and understand how Android, iOS and Windows platform works and how each framework interpret stuffs. To trim down a bit of that learning curve, I have decided to use Xamarin and Visual Studio for the following reasons:
- Xamarin is now fully integrated with the latest Visual Studio release (VS 2015 as of this writing).
- Xamarin allows you to build cross-platform apps (iOS, Andriod and Windows app) using C#.
- I am an experienced C# developer.
- I am more familiar with Visual Studio development tools.
- I don't need to learn how to use other frameworks, editors, tools and other programming languages to build native apps.
- I can take advantage of the cool features provided by Xamarin such as cloud testing and app monitoring.
- Xamarin and Visual Studio are quite popular and stable platform for building real world apps.
- Xamarin have their own dedicated support site. So when you encounter any problem during your development, you can easily post your query to their dedicated forums.
I'm writing this article so anyone that might get interested in mobile app development can reference this if they need a simple working app that requires some kind of a questionnaire to collect data from end users. This article will walk you through on building a simple survey questionnaire feature that can be integrated in your android smart watch app. Generally, a survey is a data gathering method that is utilized to collect, analyze and interpret the views of a group of people.
Before you go any further make sure that you have the necessary requirements for your system and your development environment is properly configured. For setting up the development environment in Visual Studio please refer my previous article here: Getting Started With Android Wearable Using Xamarin and Visual Studio
Let's Get Started!
For this demo, I'm going to use Visual Studio 2015 with Xamarin version 4.0. Open Visual Studio 2015 and then create a new project by selecting File > New > Project. It should bring up the following dialog below:
Under Templates select Visual C# > Android > Wear App (Android). Name your app to whatever you like but for the simplicity of this demo I just named it as "Xamarin.Messaging". Click OK to let Visual Studio generate the necessary files for our application. You should now be able to see the following screen:
The first thing we need is to add the needed images for our app. In this example, I've added two images under Resources >Drawable folder as shown below:
The images we’ve added will be used as the background for the Buttons and the other is for the question indicator.
Setting up the Model.
Now add a new class by right-clicking on the solution project and then select Add > Class. Name the class as "Messaging" and add the following properties below:
- using System;
-
- namespace Xamarin.Messaging
- {
- public class Message
- {
- public int MessageID { get; set; }
- public int MemberID { get; set; }
- public short MessageTypeID { get; set; }
- public short IconID { get; set; }
- public string MessageText { get; set; }
- public bool IsQuestion { get; set; }
- public string SelectedAnswer { get; set; }
- }
- }
The class above represents our view model that mimics the database table schema. But keep in mind that I will not be using any database here for simplicity.
The next step is to add a new class file called "Messaging". This file will contain the logic for our survey feature. Here's the code block below:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Android.OS;
- using Java.Util;
-
- namespace Xamarin.Messaging
- {
- #region MESSAGING LOGIC
- public class Messaging
- {
-
- public bool isMessageAvailable { get; set; }
-
- private Queue<Message> Messages { get; set; }
- private List<Message> AnsweredMessages { get; set; }
- private List<Message> RawMessages { get; set; }
-
- public Messaging()
- {
- this.Messages = new Queue<Message>();
- this.AnsweredMessages = new List<Message>();
- }
- public enum MessageIconType { None = 0, Question }
- public enum MessageType { None = 0, Question, Information }
- public void Add(Message message) { this.Messages.Enqueue(message); }
-
- public void Update(Message message)
- {
- this.Messages.Dequeue();
- this.AnsweredMessages.Add(message);
- }
-
- public Queue<Message> GetMessages()
- {
- var messages = GetMessagesByMemberID(1);
- messages.ToList().ForEach(x => this.Add(x));
- return this.Messages;
- }
-
- private List<Message> GetMessagesByMemberID(int memberID)
- {
- this.RawMessages = new List<Message>();
- this.RawMessages.Add(new Message() { MessageID = 1, MemberID = 1, MessageTypeID = 2, IconID = 1, MessageText = "Do you drink beer?", IsQuestion = true, SelectedAnswer = "" });
- this.RawMessages.Add(new Message() { MessageID = 2, MemberID = 1, MessageTypeID = 2, IconID = 2, MessageText = "Do you like to code?", IsQuestion = true, SelectedAnswer = "" });
- this.RawMessages.Add(new Message() { MessageID = 3, MemberID = 1, MessageTypeID = 3, IconID = 0, MessageText = "Thank you.", IsQuestion = false, SelectedAnswer = "" });
- return this.RawMessages;
- }
-
- }
- #endregion
-
- #region RUNNABLE
- public class MessageTimerTask : TimerTask
- {
- MessagingRunnableTask MRT;
- public MessageTimerTask(MessagingRunnableTask mrt) { MRT = mrt; }
- public override void Run()
- {
- MRT._handler.Post(new Action(() =>
- {
- RedirectToView(MRT);
- }));
- }
-
- void RedirectToView(MessagingRunnableTask mrt)
- {
- MainActivity m = new MainActivity();
- if (mrt._isSurveryDone)
- m.SetView("Home");
- else
- m.SetView("Survey");
- }
- }
- public class MessagingRunnableTask
- {
- MessageTimerTask _showMessageTask;
- Timer _showMessageTimer;
- public Handler _handler;
- public bool _isSurveryDone = false;
-
- public MessagingRunnableTask() { _handler = new Handler(); }
- public void ProcessMessageTask(int waitInMilliseconds, bool isDone)
- {
- _isSurveryDone = isDone;
- _showMessageTask = new MessageTimerTask(this);
- _showMessageTimer = new Timer();
- _showMessageTimer.Schedule(_showMessageTask, waitInMilliseconds);
- }
- }
- #endregion
- }
The "Messaging" class houses some properties and methods that will be used in the application. The main idea here is to use
Queue<T> for storing the list of messages from the data source so we can easily pop-out the message based on the sequence of data from the queue. The Add() method basically adds new message to the queue. The Update() method removes an existing message from the Message queue object and add a new message to the AnsweredMessages list object. GetMessages() method gets all messages that are available for a particular user. GetMessagesByMemberID() is a method where we set some dummy data to test our survey feature. In real scenarios, you may need to get the data from your database.
You may also have noticed that the file also contains the implementation for runnable. This is to schedule the survey questionnaire within a given period of time. This means that you can control as to when to prompt the users with the survey questions.
Adding the Layout
Now add a new .AXML file under Resources > Layout. Name the layout as "MessageView" as shown in the figure below:
After that switch to "Source" view in the designer and then add the following markup below:
- <?xml version="1.0" encoding="utf-8" ?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_centerHorizontal="true"
- android:maxLines="10"
- android:scrollbars="vertical">
- <ImageView android:layout_centerHorizontal="true"
- android:layout_marginTop="15.0dp"
- android:layout_width="55px"
- android:layout_height="50px"
- android:id="@+id/imgHolder" />
- <ScrollView android:minWidth="25px"
- android:minHeight="25px"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_below="@+id/imgHolder"
- android:id="@+id/scrollView1">
- <TableLayout android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:stretchColumns="1">
- <TextView android:text=""
- android:id="@+id/txtQuestion"
- android:layout_centerHorizontal="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="40dp"
- android:layout_marginBottom="10.0dp"
- android:gravity="center"
- android:layout_below="@+id/imgHolder" />
- <LinearLayout android:orientation="horizontal"
- android:paddingLeft="4.0dip"
- android:paddingTop="5.0dip"
- android:paddingRight="4.0dip"
- android:paddingBottom="1.0dip"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@+id/txtQuestion"
- android:layout_marginBottom="10.0dp"
- android:gravity="center"
- android:id="@+id/linearLayoutQuestionButtons">
- <Button android:id="@+id/btnYes"
- android:layout_width="114px"
- android:layout_height="46px"
- android:text="YES"
- android:background="@drawable/imgMessagingButton" />
- <Button android:id="@+id/btnNo"
- android:layout_width="114px"
- android:layout_height="46px"
- android:text="NO"
- android:background="@drawable/imgMessagingButton" />
- <Button android:id="@+id/btnOk"
- android:layout_width="114px"
- android:layout_height="46px"
- android:text="OK"
- android:layout_centerHorizontal="true"
- android:background="@drawable/imgMessagingButton"
- android:visibility="gone" />
- </LinearLayout>
- </TableLayout>
- </ScrollView>
- </RelativeLayout>
The markup above simply displays some Buttons, TextBox and an Image for the survey. The next step is to modify the "RectangleMain.axml" file to make it look like below:
- <?xml version="1.0" encoding="utf-8" ?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- tools:context=".MainActivity"
- tools:deviceIds="wear_round">
- <TextView android:text="Xamarin.Android Messaging Survey Sample"
- android:id="@+id/txtWelcome"
- android:layout_centerHorizontal="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="40dp"
- android:layout_marginBottom="10.0dp"
- android:gravity="center" />
- <LinearLayout android:orientation="vertical"
- android:id="@+id/layoutMessaging"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <include layout="@layout/messageview" />
- </LinearLayout>
- </LinearLayout>
The markup above includes the "MessageView" layout that we have just created earlier to the main layout.
Adding the Functionality
Now create a new class file and name it as "MessageScreen". This file serves as the code behind for the survey logic. Here's the code block below:
The class above is a partial class that implements the logic and functionality for our survey feature. It is where we initialized the controls and wired some event handlers for Buttons. It also contains some methods to do certain actions based on user interaction. For example the ToggleButtons() will show or hide a specific Button based on the question presented to the user. The rest of the methods are very much self-explanatory as the method name suggest.
Next is open up "MainActivity" class and update the code with the follwing:- using System;
-
- using Android.App;
- using Android.Content;
- using Android.Views;
- using Android.Widget;
- using Android.OS;
-
- namespace Xamarin.Messaging
- {
- [Activity(Label = "Xamarin.Messaging", MainLauncher = true, Icon = "@drawable/icon")]
- public partial class MainActivity : Activity
- {
- protected override void OnCreate(Bundle bundle)
- {
- base.OnCreate(bundle);
-
-
- SetContentView(Resource.Layout.RectangleMain);
-
- RegisterSwitchViewtReciever();
-
- MessagingRunnableTask task = new MessagingRunnableTask();
- task.ProcessMessageTask(5000, false);
- }
-
- public void SetView(string viewName)
- {
- Intent intent = new Intent("SwitchView");
- intent.PutExtra("view", viewName);
- Application.Context.SendBroadcast(intent);
- }
- public void Home()
- {
- FindViewById<TextView>(Resource.Id.txtWelcome).Visibility = ViewStates.Visible;
- FindViewById<LinearLayout>(Resource.Id.layoutMessaging).Visibility = ViewStates.Gone;
- }
-
- SwitchViewReciever switchViewReciever;
- void RegisterSwitchViewtReciever()
- {
- switchViewReciever = new SwitchViewReciever();
- switchViewReciever.ActionOnRecieve = SwitchView;
- IntentFilter filter = new IntentFilter("SwitchView");
- RegisterReceiver(switchViewReciever, filter);
- }
-
- public void SwitchView(string view)
- {
-
- FindViewById<TextView>(Resource.Id.txtWelcome).Visibility = view == "Home" ? ViewStates.Visible : ViewStates.Gone;
- FindViewById<LinearLayout>(Resource.Id.layoutMessaging).Visibility = view == "Survey" ? ViewStates.Visible : ViewStates.Gone;
-
- Action layoutAction;
- switch (view)
- {
- case "Survey":
- layoutAction = DisplayMessage;
- break;
- default:
- layoutAction = Home;
- break;
- }
- layoutAction.Invoke();
- }
-
- }
-
- public class SwitchViewReciever : BroadcastReceiver
- {
- public Action<String> ActionOnRecieve;
- public override void OnReceive(Context context, Intent intent)
- {
- ActionOnRecieve.Invoke(intent.GetStringExtra("view") ?? "Home");
- }
- }
- }
The code above is pretty much self-explanatory too. But the important thing to highlight there is the initialization and calling of the ProcessMessageTask() method. This method is responsible for displaying the survey page after 5 seconds. The RegisterSwitchViewtReciever registers the broadcast receiver so we can have access to the data from the broadcast. The SwitchViewReciever class is used to handle the data from a broadcast by implementing a BroadcastReciever. The broadcast will pass the data and tell the app whether to display the "Home" or "Survey" page.
The Output
Running the app will display like this in a real smart watch device.
On initial load
Displays the question after 5 seconds,
After all questions have been shown it will then show a “Thank You” message and return to the home view.
Thanks for reading and I hope someone finds this article useful.
Read more articles on Wearables: