如何在Android中使用signalr
我正在尝试整合signalR
在android
应用程序,但没有运气。 我一直在看各种链接,但没有一个提供有关实施的正确信息。
我有以下问题。
-
SignalR
集成必须在Service / Intent Service中完成吗? - 如果我们想通过相同的调用方法接收响应,那么如何获得?
我已经添加了三个库,即signalr android
, signalr client
和gson
但无法理解代码是如何工作的,没有适当的文档可用于理解代码。
一些问题,但没有太多的信息
Android Studio中的SignalR 无法在Android中使用SignalR实现p2p聊天
如果有人在本地应用程序的信号有经验,这将是对我非常有帮助。
更新
public class SignalRService extends Service { private static final String TAG = "Service"; private HubConnection mHubConnection; private HubProxy mHubProxy; private Handler mHandler; // to display Toast message private final IBinder mBinder = new LocalBinder(); private SharedPreferences sp; @Override public void onCreate() { super.onCreate(); Utility.showLog(TAG, "Service Created"); sp = getSharedPreferences(Utility.SHARED_PREFS, MODE_PRIVATE); mHandler = new Handler(Looper.myLooper()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { int result = super.onStartCommand(intent, flags, startId); startSignalR(); return result; } @Override public IBinder onBind(Intent intent) { startSignalR(); return mBinder; } /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { public SignalRService getService() { // Return this instance of SignalRService so clients can call public methods return SignalRService.this; } } /** * method for clients (activities) */ public void sendMessage() { String SERVER_METHOD_SEND = "iAmAvailable"; final String string = new String(); mHubProxy.invoke(new String(), SERVER_METHOD_SEND, sp.getString("user_id", null), sp.getString("pass", null), "TransMedic").done(new Action() { @Override public void run(Object o) throws Exception { Utility.showLog(TAG, o.toString()); } }).onError(new ErrorCallback() { @Override public void onError(Throwable throwable) { } }); } private void startSignalR() { Platform.loadPlatformComponent(new AndroidPlatformComponent()); String serverUrl = "http://transit.alwaysaware.org/signalr"; mHubConnection = new HubConnection(serverUrl); String SERVER_HUB_CHAT = "ChatHub"; mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT); ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger()); SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport); try { signalRFuture.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); return; } sendMessage(); } @Override public void onDestroy() { mHubConnection.stop(); super.onDestroy(); } }
服务器端:
以下是我的示例服务器端代码,您可以注意public void Send(string message)
和public void SendChatMessage(string to, string message)
。
服务器端应用程序:public void SendChatMessage(string to,string message)
- Android客户端应用程序:mHubProxy.invoke(“SendChatMessage”,receiverName,message);
服务器端应用程序:public void Send(string message)
- Android客户端应用程序:mHubProxy.invoke(“Send”,message);
namespace SignalRDemo { public class ChatHub : Hub { private static ConcurrentDictionary<string, string> FromUsers = new ConcurrentDictionary<string, string>(); // <connectionId, userName> private static ConcurrentDictionary<string, string> ToUsers = new ConcurrentDictionary<string, string>(); // <userName, connectionId> private string userName = ""; public override Task OnConnected() { DoConnect(); Clients.AllExcept(Context.ConnectionId).broadcastMessage(new ChatMessage() { UserName = userName, Message = "I'm Online" }); return base.OnConnected(); } public override Task OnDisconnected(bool stopCalled) { if (stopCalled) // Client explicitly closed the connection { string id = Context.ConnectionId; FromUsers.TryRemove(id, out userName); ToUsers.TryRemove(userName, out id); Clients.AllExcept(Context.ConnectionId).broadcastMessage(new ChatMessage() { UserName = userName, Message = "I'm Offline" }); } else // Client timed out { // Do nothing here... // FromUsers.TryGetValue(Context.ConnectionId, out userName); // Clients.AllExcept(Context.ConnectionId).broadcastMessage(new ChatMessage() { UserName = userName, Message = "I'm Offline By TimeOut"}); } return base.OnDisconnected(stopCalled); } public override Task OnReconnected() { DoConnect(); Clients.AllExcept(Context.ConnectionId).broadcastMessage(new ChatMessage() { UserName = userName, Message = "I'm Online Again" }); return base.OnReconnected(); } private void DoConnect() { userName = Context.Request.Headers["User-Name"]; if (userName == null || userName.Length == 0) { userName = Context.QueryString["User-Name"]; // for javascript clients } FromUsers.TryAdd(Context.ConnectionId, userName); String oldId; // for case: disconnected from Client ToUsers.TryRemove(userName, out oldId); ToUsers.TryAdd(userName, Context.ConnectionId); } public void Send(string message) { // Call the broadcastMessage method to update clients. string fromUser; FromUsers.TryGetValue(Context.ConnectionId, out fromUser); Clients.AllExcept(Context.ConnectionId).broadcastMessage(new ChatMessage() { UserName = fromUser, Message = message }); } public void SendChatMessage(string to, string message) { FromUsers.TryGetValue(Context.ConnectionId, out userName); string receiver_ConnectionId; ToUsers.TryGetValue(to, out receiver_ConnectionId); if (receiver_ConnectionId != null && receiver_ConnectionId.Length > 0) { Clients.Client(receiver_ConnectionId).broadcastMessage(new ChatMessage() { UserName = userName, Message = message }); } } } public class ChatMessage { public string UserName { get; set; } public string Message { get; set; } } }
客户端:
如果您在以下问题中没有阅读我的答案:
SignalR在android studio中集成
那么,这是我的工作基本代码:
public class SignalRService extends Service { private HubConnection mHubConnection; private HubProxy mHubProxy; private Handler mHandler; // to display Toast message private final IBinder mBinder = new LocalBinder(); // Binder given to clients public SignalRService() { } @Override public void onCreate() { super.onCreate(); mHandler = new Handler(Looper.getMainLooper()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { int result = super.onStartCommand(intent, flags, startId); startSignalR(); return result; } @Override public void onDestroy() { mHubConnection.stop(); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { // Return the communication channel to the service. startSignalR(); return mBinder; } /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { public SignalRService getService() { // Return this instance of SignalRService so clients can call public methods return SignalRService.this; } } /** * method for clients (activities) */ public void sendMessage(String message) { String SERVER_METHOD_SEND = "Send"; mHubProxy.invoke(SERVER_METHOD_SEND, message); } private void startSignalR() { Platform.loadPlatformComponent(new AndroidPlatformComponent()); Credentials credentials = new Credentials() { @Override public void prepareRequest(Request request) { request.addHeader("User-Name", "BNK"); } }; String serverUrl = "http://192.168.1.100"; mHubConnection = new HubConnection(serverUrl); mHubConnection.setCredentials(credentials); String SERVER_HUB_CHAT = "ChatHub"; mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT); ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger()); SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport); try { signalRFuture.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); return; } String HELLO_MSG = "Hello from Android!"; sendMessage(HELLO_MSG); String CLIENT_METHOD_BROADAST_MESSAGE = "broadcastMessage"; mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE, new SubscriptionHandler1<CustomMessage>() { @Override public void run(final CustomMessage msg) { final String finalMsg = msg.UserName + " says " + msg.Message; // display Toast message mHandler.post(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), finalMsg, Toast.LENGTH_SHORT).show(); } }); } } , CustomMessage.class); } }
活动:
public class MainActivity extends AppCompatActivity { private final Context mContext = this; private SignalRService mService; private boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(); intent.setClass(mContext, SignalRService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } super.onStop(); } public void sendMessage(View view) { if (mBound) { // Call a method from the SignalRService. // However, if this call were something that might hang, then this request should // occur in a separate thread to avoid slowing down the activity performance. EditText editText = (EditText) findViewById(R.id.edit_message); if (editText != null && editText.getText().length() > 0) { String message = editText.getText().toString(); mService.sendMessage(message); } } } /** * Defines callbacks for service binding, passed to bindService() */ private final ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to SignalRService, cast the IBinder and get SignalRService instance SignalRService.LocalBinder binder = (SignalRService.LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; }
CustomMessage类:
public class CustomMessage { public String UserName; public String Message; }
你也可以在这个GitHub链接上看到我的示例客户端项目
来自INVOKE的响应更新:
我刚刚添加了新的示例方法:
服务器端:
public string iAmAvailable(string username, string password, string message) { return "BNK Response for testing Android INVOKE"; }
客户端:
mHubProxy.invoke(String.class, "iAmAvailable", "username", "password", "TransMedic").done(new Action<String>() { @Override public void run(String s) throws Exception { Log.w("SimpleSignalR", s); } }).onError(new ErrorCallback() { @Override public void onError(Throwable throwable) { Log.e("SimpleSignalR", throwable.toString()); } });
这里是截图:
这工作对我来说:完整的源代码Android(客户端)和服务器GitHub
服务器幻灯片如果一个参数必须使用这个接口SubscriptionHandler1,如果两个参数必须使用这个interfaceSubscriptionHandler2,… …
示例两个参数,如:
服务器幻灯片
using Microsoft.AspNet.SignalR; namespace SignalRChat { public class ChatHub : Hub { public void Send(string name, string message) { // Two argument must use this interfaceSubscriptionHandler2 . Clients.All.broadcastMessage(name, message); } } }
客户幻灯片:
mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE, new SubscriptionHandler2<String, String>() { @Override public void run(final String name,final String msg) { final String finalMsg = msg.toString(); // display Toast message mHandler.post(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), finalMsg, Toast.LENGTH_SHORT).show(); } }); } } , String.class,String.class);
为了赶上所有的消息可以使用这个:
mHubConnection.received(new MessageReceivedHandler() { @Override public void onMessageReceived(final JsonElement json) { Log.e("onMessageReceived ", json.toString()); mHandler.post(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), json.toString(), Toast.LENGTH_SHORT).show(); } }); } });
对于那些在android中实现signalR客户端的人来说,这里给出的答案不能帮助接收消息,可以通过rejnev检查出这个答案。
答案实现了一个不同的方法connection.received() ,在我的情况下,它能够从服务器接收消息callback。