原文:
SignalR在Xamarin Android中的使用
ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程。实时 Web 功能是指这样一种功能:当所连接的客户端变得可用时服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。
下面介绍一下本人在Android手机开发中的使用,开发编译环境使用Xamarin。手机作为一个客户端接入服务器。
首先,在Xamarin中建立Android App,添加SignalR Client开发包,目前最新版本为2.2.0.0。
然后,添加FireHub类。FireHub类的实现代码如下:
using System; using System.Collections.Generic; using System.Text; using System.ComponentModel; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Client; using Microsoft.AspNet.SignalR.Client.Hubs; using NicoDemo.Model; namespace Nico.Android.SignalR { public class FireHub { #region 变量声明 public HubConnection _connection=null; private IHubProxy _proxy=null; public bool IsConnected = false; public delegate void ReceiveMessageDelegate(string msg); public event ReceiveMessageDelegate Receive=null; public delegate void HubCloseDelegate(); public event HubCloseDelegate CloseHub = null; public delegate void HubStatusChangedDelegate(int state,string msg); public event HubStatusChangedDelegate StateChanged = null; public delegate void AddWebMessageDelegate(WebMessage wm); public event AddWebMessageDelegate AddWebMessage = null; #endregion #region 初始化 public FireHub() { IsConnected = false; _connection = null; _proxy = null; } public string Dispose() { try { if (_connection != null) { try { _connection.Stop(); } catch { } _connection = null; } if (_proxy != null) _proxy = null; IsConnected = false; return ""; } catch(Exception err) { return string.Format("({0}-{1})",err.Message + err.StackTrace); } } #endregion #region HUB事件 void _connection_Closed() { if (CloseHub != null) CloseHub(); IsConnected = false; } void _connection_Received(string obj) { if (Receive != null) Receive(obj); } #endregion #region HUB客户端方法 public bool Connect(string url,int timeout=5000) { try { if (_connection == null) { _connection = new HubConnection(url);//,queryString); _connection.Received += _connection_Received; _connection.Closed += _connection_Closed; _connection.StateChanged += _connection_StateChanged; _proxy = _connection.CreateHubProxy("notifyHub"); } if (_connection.Start().Wait(timeout))//同步调用 { IsConnected = true; return true; } else { IsConnected = false; _connection.Dispose(); _connection = null; _proxy = null; return false; } } catch { return false; } } void _connection_StateChanged(StateChange obj) { try { switch (obj.NewState) { case ConnectionState.Disconnected: IsConnected = false; if (_connection != null) { _connection.Dispose(); _connection = null; _proxy = null; } if (StateChanged != null) StateChanged(0,""); break; } } catch(Exception err) { if (StateChanged != null) StateChanged(1, "_connection_StateChanged:"+err.Message); } } public bool ConnectToServer(UsersEntity user,int timeout=5000) { try { if (_connection == null || _proxy == null||!IsConnected) return false; return _proxy.Invoke("connect",user.ID,user.Name,user.TypeID).Wait(timeout); } catch(Exception err) { if (StateChanged != null) StateChanged(1, "ConnectToServer:"+err.Message); return false; } } public bool SendMessageToAll(UsersEntity user,string message, int timeout = 5000) { try { if (_connection == null || _proxy == null || !IsConnected) return false; _proxy.Invoke("sendMessageToAll", user.ID,user.Name,user.TypeID,message);//.Wait(timeout); return true; } catch(Exception err) { if (StateChanged != null) StateChanged(1,"SendMessageToAll:"+ err.Message); return false; } } public bool SendMessageToPrivate(string toConnID, string message) { try { if (_connection == null || _proxy == null || !IsConnected) return false; _proxy.Invoke("sendPrivateMessage", toConnID, message); return true; } catch(Exception err) { if (StateChanged != null) StateChanged(1, "SendMessageToPrivate:"+err.Message); return false; } } #endregion #region 公共函数 public bool SendToWeb(UsersEntity user,int timeout=5000) { try { // <th>事件时间</th> //<th>事件类型</th> //<th>发送者</th> //<th>单位编号</th> //<th>信息内容</th> if (!SendMessageToAll(user,"connect test", timeout)) return false; return true; } catch (Exception err) { if (StateChanged != null) StateChanged(1, "SendToWeb:"+err.Message); return false; } } #endregion } public class HubUser { [DisplayName("连接ID")] public string ConnectionId { get; set; } [DisplayName("用户ID")] public int UserID { get; set; } [DisplayName("用户名")] public string UserName { get; set; } [DisplayName("用户类型")] public int TypeID { get; set; } [DisplayName("连入时间")] public DateTime ConnectionTime { get; set; } public HubUser(string connID,int userID, string name,int typeID) { ConnectionId = connID; UserID = userID; UserName = name; TypeID = typeID; ConnectionTime = DateTime.Now; } } public class WebMessage { public string ToConnID{get;set;} public DateTime MessageDate{get;set;} public string MessageContent { get; set; } public bool IsAnswer{get;set;} public int RepeatCounts { get; set; } public bool IsRemovable { get; set; } public WebMessage() { ToConnID=string.Empty; MessageDate=DateTime.Now; MessageContent = string.Empty; IsAnswer=false; RepeatCounts = 0; IsRemovable = false; } } }
最后,在Activity中增加对FireHub的使用,参考代码如下:
public class SignalRActivity : Activity { private FireHub _fireHub = null; private UsersEntity _user = null; protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); // Create your application here SetContentView(Resource.Layout.SignalR); _user = new UsersEntity (); Button btnConnectHub = FindViewById<Button> (Resource.Id.btnConnectHub); btnConnectHub.Text = "监控网站连接"; btnConnectHub.Click += btnConnectHubClick; } protected void btnConnectHubClick(object sender,EventArgs e) { try { if (_fireHub != null) { StopHub(); lock (_syncUser) { _hubUser.Clear(); } //UpdateList(); } else { if (HubReconnect(false)) { RunOnUiThread(new Action(()=>{ _txtView.Text=string.Format("{0}: 实时网站连接成功", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));})); } else { RunOnUiThread(new Action(()=>{ _txtView.Text=string.Format("{0}: 实时网站连接失败", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));})); } } } catch (Exception err) { //FormMain.STAErrLogger.Write(string.Format("{0}({1}-{2})", err.Message, "FormMain", "btnConnectHub_Click")); } } #region HUB管理 bool HubReconnect(bool checkNull=true) { bool bRet = false; bool isUpdate = false; //重新连接到服务网站 if (!checkNull || _fireHub != null) { if (_fireHub != null) _fireHub.IsConnected = false; if (!ConnectHubServer()) { } else { bRet = true; } isUpdate = true; } return bRet; } public bool ConnectHubServer() { try { if (_fireHub == null) _fireHub = new FireHub(); else { if (_fireHub.IsConnected) return true; } if (!_fireHub.Connect("http://your service web", 5000)) { RunOnUiThread(new Action(()=>{ _txtView.Text="实时报警服务网站不在服务状态";})); if (_fireHub != null) { string strDispose = _fireHub.Dispose(); if (!string.IsNullOrEmpty(strDispose)) { //FormMain.STAErrLogger.Write(string.Format("{0}({1})", "ConnectHubServer-0", strDispose)); } } _fireHub = null; return false; } else { if (_fireHub.ConnectToServer(_user)) { _fireHub.Receive -= _fireHub_Receive; _fireHub.Receive += _fireHub_Receive; _fireHub.CloseHub -= _fireHub_CloseHub; _fireHub.CloseHub += _fireHub_CloseHub; _fireHub.StateChanged -= _fireHub_StateChanged; _fireHub.StateChanged += _fireHub_StateChanged; _fireHub.AddWebMessage -= _fireHub_AddWebMessage; _fireHub.AddWebMessage += _fireHub_AddWebMessage; if (_webMessageManage == null) { _webMessageManage = new WebMessageManage(); _webMessageManage.WebMessageCallback += _webMessageManage_WebMessageCallback; } RunOnUiThread(new Action(()=>{ _txtView.Text="成功连接到实时报警服务网站";})); } else { RunOnUiThread(new Action(()=>{ _txtView.Text="连接到实时报警服务网站失败,请重新尝试";})); string strDispose = _fireHub.Dispose(); if(!string.IsNullOrEmpty(strDispose)) { } _fireHub = null; return false; } } return true; } catch (Exception err) { return false; } } #endregion #region FireHub事件实现 void _fireHub_Receive(string msg) { try { HubMessage hm = new HubMessage(); hm = Newtonsoft.Json.JsonConvert.DeserializeObject<HubMessage>(msg); if (hm == null) return; if (hm.M == "onConnected") { #region 客户端连接成功后的反馈消息 #endregion } else if (hm.M == "onNewUserConnected") { #region 有新的客户端接入 #endregion } else if (hm.M == "onUserDisconnected") { #region 客户端断开 #endregion } else if (hm.M == "messageReceived") { #region 定时广播巡查 #endregion } else if (hm.M == "sendCallbackMessage") { #region 私人消息发出成功后,返回反馈消息 #endregion } else if (hm.M == "sendPrivateMessage") { #region 接收到私人消息 #endregion } } catch (Exception err) { RunOnUiThread(new Action(()=>{ _txtView.Text="HUB Error:" + err.Message + err.Source; })); } } void _fireHub_CloseHub() { StopHub(); } public void StopHub() { try { RunOnUiThread(new Action(()=>{ _txtView.Text="实时报警服务网站关闭"; })); if (_fireHub == null) return; string strDispose = _fireHub.Dispose(); if (!string.IsNullOrEmpty(strDispose)) { } _fireHub = null; RunOnUiThread(new Action(()=>{ ChangeHubButtonStatus(); })); } catch (Exception err) { } } void _webMessageManage_WebMessageCallback(int flag) { try { if (flag == 0) { if ((DateTime.Now - _dtHubReconnect).TotalMinutes < 30) { return; } RunOnUiThread(new Action(()=>{ })); //重新连接到服务网站 if(HubReconnect(true)) { _dtHubReconnect = DateTime.Now; } } } catch (Exception err) { } } void _fireHub_AddWebMessage(WebMessage wm) { try { if (_webMessageManage != null) { _webMessageManage.AddMessage(wm); } } catch (Exception err) { } } void _fireHub_StateChanged(int state, string msg) { try { switch (state) { case 0://断开连接了 { RunOnUiThread(new Action(()=>{ _txtView.Text="HUB掉线"; })); StopHub(); } break; case 1://HUB异常 { RunOnUiThread(new Action(()=>{ _txtView.Text=msg; })); StopHub(); } break; } } catch (Exception err) { } } #endregion }
完成以后编译通过,并且能够实现服务器和客户端的实时消息推送。