Android Wearable: 使用 Xamarin 创建简单的调查功能






4.87/5 (14投票s)
在本文中,您将学习如何使用 Xamarin 为 Android Wearable 创建一个简单的调查功能。
引言
有机会使用 Android 可穿戴设备,尤其是智能手表,这非常令人兴奋,因为现在它越来越受欢迎。构建移动和可穿戴设备应用程序并不像您想象的那么复杂。我承认,一开始,当我被分配探索和构建移动和可穿戴设备应用程序时,我有点害怕,但是使用正确的工具和技术让构建这些应用程序和原型变得对我来说更容易了。
嗯... 正确的工具?
是的,我指的是出色的 Xamarin。Xamarin 允许您为 Android、iOS 和 Windows 构建跨平台应用程序,并使用 C# 作为后端语言。他们还推出了 Xamarin Forms,允许您轻松创建可以在 Android、iOS 和 Windows Phone 中共享的原生 UI 布局。只要您了解 C#,那么为您的应用程序创建逻辑就很容易,因为您已经熟悉了语法,最重要的是 .NET 库。从 Web 过渡到移动设备时,您唯一需要学习的曲线是您需要了解和理解 Android、iOS 和 Windows 平台的工作原理以及每个框架如何解释事物。为了稍微缩短这个学习曲线,我决定使用 Xamarin 和 Visual Studio,原因如下:
- Xamarin 现在已完全集成到最新的 Visual Studio 版本中(撰写本文时为 VS 2015)。
- Xamarin 允许您使用 C# 构建跨平台应用程序(iOS、Android 和 Windows 应用程序)。
- 我是一位经验丰富的 C# 开发人员。
- 我更熟悉 Visual Studio 开发工具。
- 我无需学习使用其他框架、编辑器、工具和其他编程语言来构建原生应用程序。
- 我可以利用 Xamarin 提供的酷功能,例如云测试和应用程序监控。
- Xamarin 和 Visual Studio 是构建真实世界应用程序非常流行且稳定的平台。
- Xamarin 有自己的专用支持站点。因此,当您在开发过程中遇到任何问题时,您可以轻松地在他们的专用论坛上发布您的查询。
我写这篇文章是为了让任何可能对移动应用程序开发感兴趣的人在需要某种问卷来收集最终用户数据时参考这个简单的可用应用程序。本文将引导您完成构建一个简单的调查问卷功能,该功能可以集成到您的 Android 智能手表应用程序中。通常,调查是一种数据收集方法,用于收集、分析和解释一群人的观点。
在继续之前,请确保您的系统已满足必要的先决条件,并且您的开发环境已正确配置。有关在 Visual Studio 中设置开发环境的说明,请参阅我之前的文章:使用 Xamarin 和 Visual Studio 入门 Android Wearable
让我们开始吧!
这次,我将使用 Visual Studio 2015 和 Xamarin 版本 4.0。打开 Visual Studio 2015,然后选择“文件”>“新建”>“项目”来创建一个新项目。应该会弹出下面的对话框
图 1:Visual Studio 项目模板
在“模板”下,选择“Visual C#”>“Android”>“Wear App (Android)”。将您的应用程序命名为您喜欢的任何名称,但为了简单起见,我将其命名为“Xamarin.Messaging
”。单击“确定”让 Visual Studio 生成应用程序所需的必要文件。您现在应该能看到以下屏幕
图 2:解决方案项目
我们需要做的第一件事是为我们的应用程序添加所需的图像。在此示例中,我在 Resources > Drawable 文件夹下添加了两张图像,如下所示
图 3:资源
我们添加的图像将用作按钮的背景,另一张图像用作问题指示器。
设置模型
现在,通过右键单击解决方案项目并选择“添加”>“类”来添加一个新类。将该类命名为“Messaging
”,并添加下面的属性
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; }
}
}
上面的类代表了我们的视图模型,它模仿了数据库表架构。但请记住,为了简单起见,我将不使用任何数据库。
下一步是添加一个名为“Messaging
”的新类文件。此文件将包含我们调查功能所需的逻辑。以下是代码块
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
}
Messaging
类包含一些将在应用程序中使用的一些属性和方法。主要思想是使用 Queue<T> 来存储数据源中的消息列表,以便我们可以根据队列中的数据顺序轻松弹出消息。Add()
方法基本上会将新消息添加到队列中。Update()
方法会从 Message
队列对象中删除现有消息,并将新消息添加到 AnsweredMessages
列表对象中。GetMessages()
方法获取特定用户可用的所有消息。GetMessagesByMemberID()
是一个用于设置一些虚拟数据来测试我们调查功能的方法。在实际场景中,您可能需要从数据库或服务中获取数据。
您可能还注意到该文件还包含可运行的实现。这是为了在给定时间段内安排调查问卷。这意味着您可以控制何时向用户提示调查问题。
添加布局
现在,在 Resources > Layout 下添加一个新的 .AXML 文件。将布局命名为“MessageView
”,如下图所示
图 4:添加新视图
之后,切换到设计器中的“源”视图,然后添加下面的标记
<?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>
上面的标记简单地显示了一些按钮、文本框和用于调查的图像。下一步是修改“RectangleMain.axml”文件,使其外观如下
<?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>
上面的标记将我们刚刚创建的“MessageView
”布局包含到主布局中。
添加功能
现在,创建一个新的类文件并将其命名为“MessageScreen
”。此文件作为调查逻辑的后台代码。以下是代码块
using System;
using System.Collections.Generic;
using System.Linq;
using Android.Views;
using Android.Widget;
namespace Xamarin.Messaging
{
public partial class MainActivity
{
MessagingRunnableTask _MRT;
bool _isQuestionAvailable = true;
bool _isMessageAQuestion = true;
Messaging _message;
Queue<Message> _availableMessages;
TextView _txtQuestion;
Button _btnYes;
Button _btnNo;
Button _btnOk;
LinearLayout _llQuestionButtons;
ImageView _imgMessageIcon;
Messaging.MessageIconType _messageIconType;
Messaging.MessageType _messageType;
public void DisplayMessage()
{
InitializeObjects();
_availableMessages = _message.GetMessages();
_llQuestionButtons.Visibility = ViewStates.Visible;
_isQuestionAvailable = true;
ShowQuestion();
RunOnUiThread(WireQuestionButtons);
}
void AnswerNo_Click(object sender, EventArgs e) { ShowNextQuestion(); }
void AnswerYes_Click(object sender, EventArgs e) { ShowNextQuestion(); }
void AnswerOk_Click(object sender, EventArgs e) { ShowNextQuestion(); }
void WireQuestionButtons()
{
_btnNo.Click -= AnswerNo_Click;
_btnNo.Click += AnswerNo_Click;
_btnYes.Click -= AnswerYes_Click;
_btnYes.Click += AnswerYes_Click;
_btnOk.Click -= AnswerOk_Click;
_btnOk.Click += AnswerOk_Click;
}
void InitializeObjects()
{
_btnNo = FindViewById<Button>(Resource.Id.btnNo);
_btnYes = FindViewById<Button>(Resource.Id.btnYes);
_btnOk = FindViewById<Button>(Resource.Id.btnOk);
_txtQuestion = FindViewById<TextView>(Resource.Id.txtQuestion);
_llQuestionButtons =
FindViewById<LinearLayout>(Resource.Id.linearLayoutQuestionButtons);
_imgMessageIcon = FindViewById<ImageView>(Resource.Id.imgHolder);
_MRT = new MessagingRunnableTask();
_message = new Messaging();
}
void ToogleButtons()
{
if (_isMessageAQuestion)
{
_btnNo.Visibility = ViewStates.Visible;
_btnYes.Visibility = ViewStates.Visible;
_btnOk.Visibility = ViewStates.Gone;
}
else
{
_btnNo.Visibility = ViewStates.Gone;
_btnYes.Visibility = ViewStates.Gone;
_btnOk.Visibility = ViewStates.Visible;
}
}
void ToggleIcon(Messaging.MessageIconType iconType)
{
switch (iconType)
{
case Messaging.MessageIconType.None:
{
_imgMessageIcon.SetImageResource(0);
break;
}
case Messaging.MessageIconType.Question:
{
_imgMessageIcon.SetImageResource(Resource.Drawable.imgMessagingQuestion);
break;
}
}
}
void ToggleButtonText(Messaging.MessageType messageType)
{
switch (messageType)
{
case Messaging.MessageType.Information:
{
_btnOk.Text = "OK";
break;
}
}
}
void ShowQuestion()
{
if (_availableMessages.Any())
{
var m = _availableMessages.First();
_txtQuestion.Text = m.MessageText;
_isMessageAQuestion = m.IsQuestion;
_messageIconType = (Messaging.MessageIconType)m.IconID;
_messageType = (Messaging.MessageType)m.MessageTypeID;
_message.Update(m);//dequeue
if (!_availableMessages.Any())
_isQuestionAvailable = false;
ToggleIcon(_messageIconType);
ToogleButtons();
ToggleButtonText(_messageType);
}
else
_isQuestionAvailable = false;
}
void ShowNextQuestion()
{
if (_isQuestionAvailable)
ShowQuestion();
else
{
_btnNo.Visibility = ViewStates.Gone;
_btnYes.Visibility = ViewStates.Gone;
_llQuestionButtons.Visibility = ViewStates.Gone;
_txtQuestion.Text = "Saving...";
SaveAndBackToPreviousView(1000);
}
}
void SaveAndBackToPreviousView(int waitInMilliseconds)
{
_MRT.ProcessMessageTask(waitInMilliseconds, true);
}
}
}
上面的类是一个部分类,它实现了我们调查功能的逻辑和功能。我们在其中初始化控件并为按钮绑定了一些事件处理程序。它还包含一些方法,可以根据用户交互执行特定操作。例如,ToggleButtons()
将根据呈现给用户的问题显示或隐藏特定按钮。其余的方法非常不言自明,方法名称即表明了其含义。
MainActivity
接下来,打开“MainActivity
”类并使用以下代码更新代码
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);
// Set our view from the "main" layout resource
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");
}
}
}
上面的代码也大致不言自明。但需要强调的是初始化和调用 ProcessMessageTask()
方法。此方法负责在 5 秒后显示调查页面。RegisterSwitchViewtReciever
注册广播接收器,以便我们可以访问广播中的数据。SwitchViewReciever
类用于通过实现 BroadcastReciever
来处理来自广播的数据。广播将传递数据并告诉应用程序是显示“主页”还是“调查”页面。
输出
在真实的智能手表设备上运行应用程序将显示如下。
初始加载时
5 秒后显示问题
所有问题都显示后,将显示“谢谢
”消息并返回到主视图。
感谢阅读,希望这篇文章对您有所帮助。:)
摘要
在本文中,我们学习了如何使用 Xamarin 在我们的 Android 应用程序中实现一个简单的调查功能。