WCF 实例 —— Android 短信助手 (WCF + Android) (1)

59 篇文章 0 订阅
38 篇文章 0 订阅

http://blog.csdn.net/fangxing80/article/details/6438762


最近开始学习 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 方法到服务操作之间的映射,还定义了用于调用操作和返回结果的消息格式。

[xhtml]  view plain copy
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.web>  
  4.     <compilation debug="true" />  
  5.   </system.web>  
  6.   <system.serviceModel>  
  7.     <services>  
  8.       <service name="WCFRestHost.SmsService" behaviorConfiguration="default">  
  9.         <endpoint address="" binding="webHttpBinding" bindingConfiguration=""  
  10.           contract="WCFRestHost.SmsService">  
  11.         </endpoint>  
  12.         <host>  
  13.           <baseAddresses>  
  14.             <add baseAddress="http://localhost:8732/RestWcfSMSSvc" />  
  15.           </baseAddresses>  
  16.         </host>  
  17.       </service>  
  18.     </services>  
  19.     <behaviors>  
  20.       <serviceBehaviors>  
  21.         <behavior name="default">  
  22.           <serviceMetadata httpGetEnabled="True"/>  
  23.           <serviceDebug includeExceptionDetailInFaults="False" />  
  24.         </behavior>  
  25.       </serviceBehaviors>  
  26.     </behaviors>  
  27.   </system.serviceModel>  
  28. </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往容器里放入一条短信对象。 流程比较简单,大家一看就明白啦。 

[c-sharp]  view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Runtime.Serialization;  
  5. using System.ServiceModel;  
  6. using System.Text;  
  7. using System.ServiceModel.Web;  
  8. using System.ComponentModel;  
  9. namespace WCFRestHost  
  10. {  
  11.     [ServiceContract]  
  12.     [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]  
  13.     public class SmsService  
  14.     {  
  15.         static SmsService()  
  16.         {  
  17.             SmsList = new BindingList<SmsData>();  
  18.         }  
  19.         public static BindingList<SmsData> SmsList  
  20.         {  
  21.             get;  
  22.             private set;  
  23.         }  
  24.         public static event Action<SmsData> OnSmsRecieved;  
  25.         public static void AddData(SmsData data)  
  26.         {  
  27.             lock (SmsList)  
  28.             {  
  29.                 SmsList.Add(data);  
  30.             }  
  31.         }  
  32.         [OperationContract]  
  33.         [WebInvoke(UriTemplate="SetData", Method="POST", RequestFormat=WebMessageFormat.Json)]  
  34.         public void SetData(SmsData data)  
  35.         {  
  36.             var ctx = WebOperationContext.Current;  
  37.             data.SmsTime = DateTime.Now.ToString("MM-dd HH:mm:ss");  
  38.             //SmsList.Add(data);  
  39.             if (OnSmsRecieved != null)  
  40.                 OnSmsRecieved(data);  
  41.             ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;  
  42.         }  
  43.         [OperationContract]  
  44.         [WebGet(UriTemplate = "GetData", ResponseFormat = WebMessageFormat.Json)]  
  45.         public SmsData GetData()  
  46.         {  
  47.             var ctx = WebOperationContext.Current;  
  48.             var data = SmsList.FirstOrDefault(sms => sms.State == 1);  
  49.             if (data != null)  
  50.             {  
  51.                 data.State = 2;  
  52.                 data.SmsTime = DateTime.Now.ToString("MM-dd HH:mm:ss");  
  53.             }  
  54.             ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;  
  55.             return data;  
  56.         }  
  57.     }  
  58.     public class SmsData  
  59.     {  
  60.         public string Phone { getset; }  
  61.         public string Content { getset; }  
  62.         public string SmsTime { getset; }  
  63.         public string Name { getset; }  
  64.         // 0: recieved 1: presend 2: send  
  65.         public int State { getset; }  
  66.     }  
  67. }  
 
其次,ServiceHost 选择 WebServiceHost 类来承载利用 REST 编程模型的服务。即支持REST风格的Http Uri到服务方法的映射。另外,在 Winform 中 Host 为了让WCF 服务的通信不影响 UI 线程,需要为 WebServiceHost 单独创建线程。 

[c-sharp]  view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.ServiceModel;  
  6. using System.Threading;  
  7. namespace WCFRestHost  
  8. {  
  9.     public class ThreadedServiceHost<T> : IDisposable where T : ServiceHostBase  
  10.     {  
  11.         const int SleepTime = 100;  
  12.         private ServiceHostBase _serviceHost = null;  
  13.         private Thread _thread;  
  14.         private bool _isRunning;  
  15.         public ThreadedServiceHost(Type serviceType)  
  16.         {  
  17.             _serviceHost = (ServiceHostBase)Activator.CreateInstance(typeof(T), new object[] { serviceType });  
  18.             _thread = new Thread(ThreadMethod);  
  19.         }  
  20.         void ThreadMethod()  
  21.         {  
  22.             try  
  23.             {  
  24.                 _isRunning = true;  
  25.                 _serviceHost.Open();  
  26.                 while (_isRunning)  
  27.                 {  
  28.                     Thread.Sleep(SleepTime);  
  29.                 }  
  30.                 _serviceHost.Close();  
  31.             }  
  32.             catch (Exception)  
  33.             {  
  34.                 if (_serviceHost != null)  
  35.                 {  
  36.                     _serviceHost.Close();  
  37.                 }  
  38.             }  
  39.         }  
  40.         public void Open()  
  41.         {  
  42.             _thread.Start();  
  43.         }  
  44.         public void Stop()  
  45.         {  
  46.             lock (this)  
  47.             {  
  48.                 _isRunning = false;  
  49.             }  
  50.         }  
  51.         public void Dispose()  
  52.         {  
  53.             Stop();  
  54.         }  
  55.     }  
  56. }  
 

服务端UI:

[c-sharp] view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.ComponentModel;  
  4. using System.Data;  
  5. using System.Drawing;  
  6. using System.Linq;  
  7. using System.Text;  
  8. using System.Windows.Forms;  
  9. using System.ServiceModel.Web;  
  10. namespace WCFRestHost  
  11. {  
  12.     public partial class frmMain : Form  
  13.     {  
  14.         public frmMain()  
  15.         {  
  16.             InitializeComponent();  
  17.         }  
  18.         private ThreadedServiceHost<WebServiceHost> _threadHost;  
  19.         private void frmMain_Load(object sender, EventArgs e)  
  20.         {  
  21.             _threadHost = new ThreadedServiceHost<WebServiceHost>(typeof(SmsService));  
  22.             _threadHost.Open();  
  23.             tssStatus.Text = "Listener is opening ...";  
  24.             SmsService.OnSmsRecieved += new Action<SmsData>(SmsService_OnSmsRecieved);  
  25.             DataBind();  
  26.         }  
  27.         void SmsService_OnSmsRecieved(SmsData obj)  
  28.         {  
  29.             Action<SmsData> addData = d => SmsService.AddData(d);  
  30.             dgvSms.Invoke(addData, obj);  
  31.         }  
  32.         private void DataBind()  
  33.         {  
  34.             dgvSms.DataSource = SmsService.SmsList;  
  35.             dgvSms.ClearSelection();  
  36.             txtPhone.DataBindings.Add("Text", SmsService.SmsList, "Phone");  
  37.             txtTime.DataBindings.Add("Text", SmsService.SmsList, "SmsTime");  
  38.             txtContent.DataBindings.Add("Text", SmsService.SmsList, "Content");  
  39.         }  
  40.         private void frmMain_FormClosing(object sender, FormClosingEventArgs e)  
  41.         {  
  42.             if (_threadHost != null)  
  43.                 _threadHost.Stop();  
  44.         }  
  45.         private void btnQuit_Click(object sender, EventArgs e)  
  46.         {  
  47.             this.Close();  
  48.         }  
  49.         private void btnSend_Click(object sender, EventArgs e)  
  50.         {  
  51.             var smsForm = new SendSms();  
  52.             smsForm.ShowDialog();  
  53.             //DataBind();  
  54.         }  
  55.         private void button1_Click(object sender, EventArgs e)  
  56.         {  
  57.             SmsService.SmsList.Add(new SmsData { Phone = "1" });  
  58.         }  
  59.     }  
  60. }  

注意:当收到短信时直接添加到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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值