最近开始学习 Android,为了更快上手于是给自己找个小课题来练习一下: WCF作为服务端开放RESTful Service,Android作为客户端将手机上的短信传给服务端显示,并轮询服务端是否有发送的短信取回并发送。(在电脑前就可以浏览即时的短信并能快速回复,呵呵还是挺有意思的)。先上几张图:

1. 客户端:(咦?怎么还用android1.5?没办法现在手机是1.5的,为了在真机上发布凑合用吧:))

2. 服务端:


其中涉及到的知识点如下:(恩文章标题有点跑偏了,其实大头在Android端。。。)

1. 服务端:
(1) RESTful WCF 如何作成 Winform Host
(2) WCF 服务在 Winform Host 如何与服务端的UI进行数据交互
2. 客户端:
(1) Android Timer 的应用
(2) Android Http 的交互
(3) Android Json数据的序列化/反序列化
(4) Android 短信拦截器的使用
(5) Android Sqlite 查询

服务端
(1) RESTful WCF 如何作成 Winform Host

首先Binding 选择 webHttpBinding使用WebGetAttribute或WebInvokeAttribute特性对各个服务操作进行批注。这定义了从 URI 和 HTTP 方法到服务操作之间的映射,还定义了用于调用操作和返回结果的消息格式。

<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.web> <compilation debug="true" /> </system.web> <system.serviceModel> <services> <service name="WCFRestHost.SmsService" behaviorConfiguration="default"> <endpoint address="" binding="webHttpBinding" bindingConfiguration="" contract="WCFRestHost.SmsService"> </endpoint> <host> <baseAddresses> <add baseAddress="http://localhost:8732/RestWcfSMSSvc" /> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors> <behavior name="default"> <serviceMetadata httpGetEnabled="True"/> <serviceDebug includeExceptionDetailInFaults="False" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
(2) WCF 服务在 Winform Host 如何与服务端的UI进行数据交互

服务端代码,没什么特别的。一开始考虑用socket,但是socket自己维护双工通信太麻烦了,于是想到了WCF,在Winform Host下发布一个RESTful WCF服务,而作为客户端的Android实现Http通信也不是什么难事,服务端直接反序列化成服务端对象编码很便利。
WCF服务里公开一个static的BindingList<SmsData>作为短信容器(Tip:使用BindingList<T>可以使得数据源变化立即反映到UI上,相比之下List<T>可以说只是Oneway的容器),PC端可以通过UI往里添加要发送的短信,客户端则轮询取出要发送的短信进行发送;当客户端收到短信则通过WCF往容器里放入一条短信对象。 流程比较简单,大家一看就明白啦。

using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; using System.ServiceModel.Web; using System.ComponentModel; namespace WCFRestHost { [ServiceContract] [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class SmsService { static SmsService() { SmsList = new BindingList<SmsData>(); } public static BindingList<SmsData> SmsList { get; private set; } public static event Action<SmsData> OnSmsRecieved; public static void AddData(SmsData data) { lock (SmsList) { SmsList.Add(data); } } [OperationContract] [WebInvoke(UriTemplate="SetData", Method="POST", RequestFormat=WebMessageFormat.Json)] public void SetData(SmsData data) { var ctx = WebOperationContext.Current; data.SmsTime = DateTime.Now.ToString("MM-dd HH:mm:ss"); //SmsList.Add(data); if (OnSmsRecieved != null) OnSmsRecieved(data); ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK; } [OperationContract] [WebGet(UriTemplate = "GetData", ResponseFormat = WebMessageFormat.Json)] public SmsData GetData() { var ctx = WebOperationContext.Current; var data = SmsList.FirstOrDefault(sms => sms.State == 1); if (data != null) { data.State = 2; data.SmsTime = DateTime.Now.ToString("MM-dd HH:mm:ss"); } ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK; return data; } } public class SmsData { public string Phone { get; set; } public string Content { get; set; } public string SmsTime { get; set; } public string Name { get; set; } // 0: recieved 1: presend 2: send public int State { get; set; } } }
其次,ServiceHost 选择 WebServiceHost类来承载利用 REST 编程模型的服务。即支持REST风格的Http Uri到服务方法的映射。另外,在 Winform 中 Host 为了让WCF 服务的通信不影响 UI 线程,需要为 WebServiceHost 单独创建线程。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.Threading; namespace WCFRestHost { public class ThreadedServiceHost<T> : IDisposable where T : ServiceHostBase { const int SleepTime = 100; private ServiceHostBase _serviceHost = null; private Thread _thread; private bool _isRunning; public ThreadedServiceHost(Type serviceType) { _serviceHost = (ServiceHostBase)Activator.CreateInstance(typeof(T), new object[] { serviceType }); _thread = new Thread(ThreadMethod); } void ThreadMethod() { try { _isRunning = true; _serviceHost.Open(); while (_isRunning) { Thread.Sleep(SleepTime); } _serviceHost.Close(); } catch (Exception) { if (_serviceHost != null) { _serviceHost.Close(); } } } public void Open() { _thread.Start(); } public void Stop() { lock (this) { _isRunning = false; } } public void Dispose() { Stop(); } } }

服务端UI:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.ServiceModel.Web; namespace WCFRestHost { public partial class frmMain : Form { public frmMain() { InitializeComponent(); } private ThreadedServiceHost<WebServiceHost> _threadHost; private void frmMain_Load(object sender, EventArgs e) { _threadHost = new ThreadedServiceHost<WebServiceHost>(typeof(SmsService)); _threadHost.Open(); tssStatus.Text = "Listener is opening ..."; SmsService.OnSmsRecieved += new Action<SmsData>(SmsService_OnSmsRecieved); DataBind(); } void SmsService_OnSmsRecieved(SmsData obj) { Action<SmsData> addData = d => SmsService.AddData(d); dgvSms.Invoke(addData, obj); } private void DataBind() { dgvSms.DataSource = SmsService.SmsList; dgvSms.ClearSelection(); txtPhone.DataBindings.Add("Text", SmsService.SmsList, "Phone"); txtTime.DataBindings.Add("Text", SmsService.SmsList, "SmsTime"); txtContent.DataBindings.Add("Text", SmsService.SmsList, "Content"); } private void frmMain_FormClosing(object sender, FormClosingEventArgs e) { if (_threadHost != null) _threadHost.Stop(); } private void btnQuit_Click(object sender, EventArgs e) { this.Close(); } private void btnSend_Click(object sender, EventArgs e) { var smsForm = new SendSms(); smsForm.ShowDialog(); //DataBind(); } private void button1_Click(object sender, EventArgs e) { SmsService.SmsList.Add(new SmsData { Phone = "1" }); } } }
注意:当收到短信时直接添加到BindingList<SmsData>中时会导致"跨线程更新UI的错误",因为WCF服务实际在子线程中,所以添加SmsData的操作必须使用Control.Invoke 进行调用,但是又不想把UI的引用直接交给WCF服务。。。呵呵,使用事件机制就可以很好的解决这一问题,让服务通知UI有新数据并让UI自己取添加数据。可以看到上面的服务代码中,公开了一个OnSmsRecieved事件。这样UI端监听这个事件,再使用 Control.Invoke 调用 AddData 方法。怎么样是不是很简单?不过每条短信是花1毛钱的T_T


OK,接下来介绍下android端的代码:WCF 实例 —— Android 短信助手 (WCF + Android) (2)

更多相关文章

  1. Android(安卓)中的 Service 全面总结
  2. Android系统服务-简介
  3. Android(安卓)Binder概述
  4. Android(安卓)系统中 gps Location Service 的实现与架构,本文可
  5. Android和设计模式:代理模式
  6. Android(安卓)IPC机制(三)在Android(安卓)Studio中使用AIDL实现跨
  7. Android中的服务(service)详解(三)--远程服务(remote)
  8. 《Android/OPhone 开发完全讲义》样章和目录下载
  9. Android实现远程控制PC(Android[客户端]+Qt[服务器端])

随机推荐

  1. Android(安卓)CheckBox使密码可见/隐藏
  2. Android(安卓)获取ip地址
  3. Android(安卓)8.0新特性调研
  4. Android(安卓)网页加载完成ProgressDialo
  5. Android悬浮框
  6. [转帖] android平台刷机包的制作研究 1~2
  7. android ImageView的scaleType属性
  8. android SwitchPreference ListPreferenc
  9. Android(安卓)加密解密 DES BASE64 MD5 U
  10. Android(安卓)Export aborted because fa