signalR
アプリにAndroid
を統合しようとしていますが、運はありません。私はさまざまなリンクを見てきましたが、どのリンクも実装に関する適切な情報を提供していません。
以下の質問があります。
SignalR
統合は、Service/Intent Service内で行う必要がありますか?3つのライブラリ、つまりsignalr Android
、signalr client
およびgson
が、コードの動作を理解できないため、コードを理解するための適切なドキュメントがありません。
質問のいくつかは尋ねられましたが、あまり情報はありません
SignalR in Android StudioAndroidで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();
}
}
2018年更新:
SignalR.net Coreを使用している場合は、 このライブラリ を使用します。そうしないと、接続時にエラーが発生します。
サーバー側:
以下は私のサーバー側コードのサンプルです。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; }
}
}
クライアント側:
次の質問で私の答えを読んでいない場合:
次に、ここに私の動作する基本的なコードがあります:
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;
}
また、 this GitHub link で私のサンプルクライアントプロジェクトを見ることができます
呼び出しからの応答の更新:
新しいサンプルメソッドを追加しました。
サーバー側:
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
サーバースライド2つの引数がこのinterfaceSubscriptionHandler2を使用する必要がある場合、1つの引数がこのインターフェイスSubscriptionHandler1を使用する必要がある場合、...
次のような2つの引数のサンプル:
サーバースライド:
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);
Catchでは、すべてのメッセージでこれを使用できます。
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();
}
});
}
});
SignalRチームは最近、ASP.NET Core SignalR用のJavaクライアントをリリースしました。これは入門ドキュメントへのリンクです https://docs.Microsoft.com/en-us/ aspnet/core/signalr/Java-client?view = aspnetcore-2.2
SignalRクライアントをAndroidで実装していて、ここで与えられた答えはメッセージを受信するのに役立たない場合this =rejnevによる回答。
答えは、私の場合、サーバーからメッセージコールバックを受信できる別のメソッドconnection.received()を実装しています。