WCF 執行個體 —— Android 簡訊助手 (WCF + Android) (1)

來源:互聯網
上載者:User

最近開始學習 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" ?><br /><configuration><br /> <system.web><br /> <compilation debug="true" /><br /> </system.web><br /> <system.serviceModel><br /> <services><br /> <service name="WCFRestHost.SmsService" behaviorConfiguration="default"><br /> <endpoint address="" binding="webHttpBinding" bindingConfiguration=""<br /> contract="WCFRestHost.SmsService"><br /> </endpoint><br /> <host><br /> <baseAddresses><br /> <add baseAddress="http://localhost:8732/RestWcfSMSSvc" /><br /> </baseAddresses><br /> </host><br /> </service><br /> </services><br /> <behaviors><br /> <serviceBehaviors><br /> <behavior name="default"><br /> <serviceMetadata httpGetEnabled="True"/><br /> <serviceDebug includeExceptionDetailInFaults="False" /><br /> </behavior><br /> </serviceBehaviors><br /> </behaviors><br /> </system.serviceModel><br /></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;<br />using System.Collections.Generic;<br />using System.Linq;<br />using System.Runtime.Serialization;<br />using System.ServiceModel;<br />using System.Text;<br />using System.ServiceModel.Web;<br />using System.ComponentModel;<br />namespace WCFRestHost<br />{<br /> [ServiceContract]<br /> [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]<br /> public class SmsService<br /> {<br /> static SmsService()<br /> {<br /> SmsList = new BindingList<SmsData>();<br /> }<br /> public static BindingList<SmsData> SmsList<br /> {<br /> get;<br /> private set;<br /> }<br /> public static event Action<SmsData> OnSmsRecieved;<br /> public static void AddData(SmsData data)<br /> {<br /> lock (SmsList)<br /> {<br /> SmsList.Add(data);<br /> }<br /> }<br /> [OperationContract]<br /> [WebInvoke(UriTemplate="SetData", Method="POST", RequestFormat=WebMessageFormat.Json)]<br /> public void SetData(SmsData data)<br /> {<br /> var ctx = WebOperationContext.Current;<br /> data.SmsTime = DateTime.Now.ToString("MM-dd HH:mm:ss");<br /> //SmsList.Add(data);<br /> if (OnSmsRecieved != null)<br /> OnSmsRecieved(data);<br /> ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;<br /> }<br /> [OperationContract]<br /> [WebGet(UriTemplate = "GetData", ResponseFormat = WebMessageFormat.Json)]<br /> public SmsData GetData()<br /> {<br /> var ctx = WebOperationContext.Current;<br /> var data = SmsList.FirstOrDefault(sms => sms.State == 1);<br /> if (data != null)<br /> {<br /> data.State = 2;<br /> data.SmsTime = DateTime.Now.ToString("MM-dd HH:mm:ss");<br /> }<br /> ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;<br /> return data;<br /> }<br /> }<br /> public class SmsData<br /> {<br /> public string Phone { get; set; }<br /> public string Content { get; set; }<br /> public string SmsTime { get; set; }<br /> public string Name { get; set; }<br /> // 0: recieved 1: presend 2: send<br /> public int State { get; set; }<br /> }<br />}<br /> 
其次,ServiceHost 選擇 WebServiceHost 類來承載利用 REST 編程模型的服務。即支援REST風格的Http Uri到服務方法的映射。另外,在 Winform 中 Host 為了讓WCF 服務的通訊不影響 UI 線程,需要為 WebServiceHost 單獨建立線程。 

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

服務端UI:
using System;<br />using System.Collections.Generic;<br />using System.ComponentModel;<br />using System.Data;<br />using System.Drawing;<br />using System.Linq;<br />using System.Text;<br />using System.Windows.Forms;<br />using System.ServiceModel.Web;<br />namespace WCFRestHost<br />{<br /> public partial class frmMain : Form<br /> {<br /> public frmMain()<br /> {<br /> InitializeComponent();<br /> }<br /> private ThreadedServiceHost<WebServiceHost> _threadHost;<br /> private void frmMain_Load(object sender, EventArgs e)<br /> {<br /> _threadHost = new ThreadedServiceHost<WebServiceHost>(typeof(SmsService));<br /> _threadHost.Open();<br /> tssStatus.Text = "Listener is opening ...";<br /> SmsService.OnSmsRecieved += new Action<SmsData>(SmsService_OnSmsRecieved);<br /> DataBind();<br /> }<br /> void SmsService_OnSmsRecieved(SmsData obj)<br /> {<br /> Action<SmsData> addData = d => SmsService.AddData(d);<br /> dgvSms.Invoke(addData, obj);<br /> }<br /> private void DataBind()<br /> {<br /> dgvSms.DataSource = SmsService.SmsList;<br /> dgvSms.ClearSelection();<br /> txtPhone.DataBindings.Add("Text", SmsService.SmsList, "Phone");<br /> txtTime.DataBindings.Add("Text", SmsService.SmsList, "SmsTime");<br /> txtContent.DataBindings.Add("Text", SmsService.SmsList, "Content");<br /> }<br /> private void frmMain_FormClosing(object sender, FormClosingEventArgs e)<br /> {<br /> if (_threadHost != null)<br /> _threadHost.Stop();<br /> }<br /> private void btnQuit_Click(object sender, EventArgs e)<br /> {<br /> this.Close();<br /> }<br /> private void btnSend_Click(object sender, EventArgs e)<br /> {<br /> var smsForm = new SendSms();<br /> smsForm.ShowDialog();<br /> //DataBind();<br /> }<br /> private void button1_Click(object sender, EventArgs e)<br /> {<br /> SmsService.SmsList.Add(new SmsData { Phone = "1" });<br /> }<br /> }<br />}
注意:當收到簡訊時直接添加到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)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.