Работа с SignalR из Android

в 20:41, , рубрики: Песочница, метки: ,

Итак, после долгих мучений, наконец, мне удалось разобраться со всем функционалом (что мне нужно было для моей работы), что есть в библиотеке Signal R для Android.

Самое главное, это jar файлы, которые нужны нашей программе для подключения и работы с сервером.
Их можно скачать из моего сайта, хотя вы тоже сами можете из сделать из Github:
http://smartarmenia.com/android_libs/signalr-client-sdk.jar
http://smartarmenia.com/android_libs/signalr-client-sdk-android.jar

Еще нам нужна библиотека gson, которую можно добавить из maven dependencies в Android Studio или скачать из google для Eclipse.

Так, после добавления этих библиотек в папку libs нашего проекта, можно уже подключиться к серверу.

Я на своем примере буду все делать из сервиса и AsyncTask-ами, как и откуда делать — будете вы решать сами.

Первое, что нужно делать — это вызвать статический метод до того, как начнем использовать signalr в Android.

Platform.loadPlatformComponent(new AndroidPlatformComponent());

Потом создаем connection и hub(s):

HubConnection connection = new HubConnection("signalr_host");
HubProxy mainHubProxy = connection.createHubProxy("MainHub");

После этого нам надо отловить state_change события, чтобы контролировать нашим соединением.

connection.stateChanged(new StateChangedCallback() {
            @Override
            public void stateChanged(ConnectionState connectionState, ConnectionState connectionState2) {
                Log.i("SignalR", connectionState.name() + "->" + connectionState2.name());
            }
        });

это для изменения state (Disconnected, Connecting, Connected, Reconnecting)

Теперь отловим событие отсоединения:

connection.closed(new Runnable() {
            @Override
            public void run() {
                Log.i("SignalR", "Closed");
                connectSignalr();
            }
        });

Функция, которая вызывает AsyncTask соединения (эту функцию нужно вызвать в начале сервиса и при Disconnect (Close)):

private void connectSignalr() {
        try {
            SignalRConnectTask signalRConnectTask = new SignalRConnectTask();
            signalRConnectTask.execute(connection);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

Код класса SignalRConnectTask:

public class SignalRConnectTask extends AsyncTask {
    @Override
    protected Object doInBackground(Object[] objects) {
        HubConnection connection = (HubConnection) objects[0];
        try {
            Thread.sleep(2000);
            connection.start().get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return null;
    }
}

У нас уже есть рабочее подключение к серверу. В дальнейшем нам понадобится подписаться к событиям или вызвать функции hub-а.

subscribe

mainHubProxy.subscribe("newClient").addReceivedHandler(new Action<JsonElement[]>() {
            @Override
            public void run(JsonElement[] jsonElements) throws Exception {
                Log.i("SignalR", "Message From Server: " + jsonElements[0].getAsString());
            }
        });

В массиве jsonElements — данные, которые нам отправил сервер, они могут быть любого serializable типа. В основном мы знаем, какого они типа и можем преобразовать на нужный тип. Примеры делайте сами, но если будут вопросы или нужны будут примеры, напишите в комментариях.

invoke

Это — для вызова метода hub-а. У нас есть 2 варианта, вызов метода, который возвращает результат и ничего не возвращает (Void).

Сначала посмотрим Void:

public class SignalRTestActionTask extends AsyncTask {
    @Override
    protected Object doInBackground(Object[] objects) {
        if (connection.getState() == ConnectionState.Connected) {
            Object param1 = objects[0];
            Object param2 = objects[1];
            try {
                mainHubProxy.invoke("TestMethod", param1, param2).get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    protected void onPostExecute(Object o) {
        super.onPostExecute(o);
    }
}

new SignalRTestActionTask().execute(new Object(), new Object());

Опять же, создаем AsyncTask для выполнения задачи.

Теперь тоже самое сделаем и для другого варианта invoke, который возвращает результат.

public class SignalRTestActionWithResultTask extends AsyncTask {
    @Override
    protected Object doInBackground(Object[] objects) {
        if (connection.getState() == ConnectionState.Connected) {
            Object result = null;
            Object param1 = objects[0];
            Object param2 = objects[1];
            try {
                result = mainHubProxy.invoke(Object.class, "TestMethod", param1, param2).get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    @Override
    protected void onPostExecute(Object o) {
        super.onPostExecute(o);
        // Тут идет обработка результата.
    }
}

new SignalRTestActionWithResultTask().execute(new Object(), new Object());

Все просто.

Далее настало время десериализации json-а в классы.

Например, наш метод в signalr возвращает String — и мы это знаем.
Для этого мы просто передаем функцию invoke тип результата метода и полученный результат с помощью gson преобразует данные в нужный тип.

String result = mainHubProxy.invoke(String.class, "TestMethod", param1, param2).get();

Когда приходит json array, то тип передаем array, так:

String[] result = mainHubProxy.invoke(String[].class, "TestMethod", param1, param2).get();

Ну а наш array легко можно преобразовать в List:

List<String> strings = Arrays.asList(result);

Как тип возвращаемого результата можно задать любой сериализуемый тип, например, сами можем создать собственный класс со структурой json объекта. Но это чудеса библиотеки gson, которому эта статья не посвящена.

Вот и все, наверное. Если будут вопросы и/или замечания, напишите, разберемся вместе.

Поделиться

* - обязательные к заполнению поля