Как подключиться к веб-сокету в Android - PullRequest
1 голос
/ 12 октября 2019

Я учусь использовать WebSockets в Spring boot с Android client. Я взял Scarlet by Tinder, похоже, отличная библиотека. Моя проблема, хотя, как назвать мою websocket конечную точку в алом. У меня уже есть рабочий пример spring boot проекта, который постоянно обновляет местоположение пользователей, ниже находится проект

Во-первых, у нас есть наш брокер сообщений WebSocketMessageBrokerConfigurer

public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/ws").withSockJS();
}

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.setApplicationDestinationPrefixes("/app");
}

}

Наш слушатель, который слушаетсоединения / разъединения, а также загрузки страниц

@Component

public class WebSocketEventListener {

private static final Logger logger = LoggerFactory.getLogger(WebSocketEventListener.class);

@Autowired
private SimpMessageSendingOperations messagingTemplate;

//method called when user open page in browser
@EventListener
public void handleWebSocketConnectListener(SessionConnectedEvent event) {
    logger.info("Received a new web socket connection");
}

//method called when user close page in browser
@EventListener
public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
    StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());

    String username = (String) headerAccessor.getSessionAttributes().get("username");
    if(username != null) {
        logger.info("User Disconnected : " + username);

        //remove user from latest Location Feed
        CommunicationController.latestLocationFeed.remove(username);

        //transmitting current user's latest location feed
        messagingTemplate.convertAndSend("/app/getData", new LocationBean());
    }
}
}

И, наконец, наш контроллер, в основном с 1 конечной точкой, который сохраняет и обновляет всех пользователей новыми местоположениями, которые подписаны на /app/getData

public static Map<String, LocationBean> latestLocationFeed = new HashMap<String, LocationBean>();

@MessageMapping("/saveLocation") //for saving current user's location in memory
@SendTo("/app/getData") //for transmitting all connected user's latest location 
public List<LocationBean> saveLocation(@Payload LocationBean bean, SimpMessageHeaderAccessor headerAccessor) {
    //getting current user's location from web socket
    headerAccessor.getSessionAttributes().put("username", bean.getUser());
    logger.debug("\tUser:"+bean.getUser()+" >>> LocationBean:"+bean.toString());

    //unique user wise latest location feed set in-memory hash map
    latestLocationFeed.put(bean.getUser(), bean);

    //converting map to list
    Collection<LocationBean> values = latestLocationFeed.values();
    ArrayList<LocationBean> listOfValues = new ArrayList<LocationBean>(values);
    logger.info("\tPublicLocationFeed:"+listOfValues.toString());

    //send all user's latest location feed
    return listOfValues;
}

Использовать это в Интернете очень просто, в идеале у нас есть SockJS и Stomp. Сначала мы инициализируем SockJS с нашей зарегистрированной конечной точкой registry.addEndpoint("/ws").withSockJS() при весенней загрузке, как var socket = new SockJS('/ws');

Затем создаемэкземпляр StompClient из SockJS как `` `stompClient = Stomp.over (сокет);` `` `

И, наконец, подключиться stompClient.connect({}, whenConnected, whenError);

Как только мы подключимся, мы можемзатем subscribe на наш /app/getData, который обновляет нас новыми местоположениями пользователей, такими как stompClient.subscribe('/app/getData', whenMessageReceived);

И в случае, если мы хотим отправить наше новое местоположение, мы можем сделать это с конечной точкой /app/saveLocation, такой как stompClient.send( "/app/saveLocation", {}, getLocationBean() );

И так простотак как у нас работает сеть, моя проблема в том, как сделать этот точный процесс в Android, используя алый. Кажется, я не могу даже получить URL правильно, я всегда получаю ответ о сбое соединения. Мой сервис выглядит следующим образом:

public interface GdaxService {
@Receive
Flowable<WebSocket.Event> observeWebSocketEvent();

@Send
void sendSubscribe(String message);

@Receive
Flowable<String> observeLocationChangedResponse();
}

И я реализую его как

    OkHttpClient okHttpClient = new OkHttpClient
            .Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10,TimeUnit.SECONDS)
            .build();

    GdaxService scarletGdaxService = new Scarlet.Builder()
            //.lifecycle(this)
            .webSocketFactory(OkHttpClientUtils.newWebSocketFactory(okHttpClient, "ws://localhost:8080/ws/app/getData"))
            .addMessageAdapterFactory(new GsonMessageAdapter.Factory())
            .addStreamAdapterFactory(new RxJava2StreamAdapterFactory())
            .build()
            .create(GdaxService.class);



    scarletGdaxService.observeWebSocketEvent()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new DisposableSubscriber<WebSocket.Event>() {
                @Override
                public void onNext(WebSocket.Event event) {
                    Log.d(TAG, "Current socket connection status: "+event);
                }

                @Override
                public void onError(Throwable t) {
                    t.printStackTrace();
                }

                @Override
                public void onComplete() {
                    Log.d(TAG, "Connection status flowable complete");
                }
            });
    scarletGdaxService.observeLocationChangedResponse()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new DisposableSubscriber<String>() {
                @Override
                public void onNext(String s) {
                    txtResponse.setText(s);
                }

                @Override
                public void onError(Throwable t) {
                    t.printStackTrace();
                }

                @Override
                public void onComplete() {
                    Log.d(TAG, "Flowable has completed");
                }
            });

. Любой, кто имеет опыт репликации моей веб-реализации в Android, может помочь.

...