Fun with WebSockets in Android
WebSockets provide a two-way, realtime, communication stream between endpoints.
To demonstrate how this can be used in an Android project, let’s build a simple drawing app.
We’ll create a fragment with a canvas on which we can draw images. This will stream the drawing actions in realtime to a desktop website (connected to the same WiFi access point).
The full source code is here, follow the README to get set up.
Server-side Implementation
Our server for this demo is the Android app with the WebSocket dependency being provided by our awesome friend Ktor.
Drawing code
The drawing part of this project is a straightforward custom view on which we listen for MotionEvents and do the following :
- Draw a line to the touched point on the view’s canvas
- Provide the x,y coordinates to the server for forwarding to the client via Fragment -> ViewModel -> Server
See the full implementation for more details.
Server code
At the app’s core we have an embedded server powered by Jetty containing an endpoint for root (“/”) where we listen for incoming connections on port 8080 and, once connected, can send and receive blocks of data (called frames).
We need to stay in this session block in order to listen to the incoming data and send outgoing data, luckily this is a coroutine so we can use while(coroutine.isActive) { // do work }
i.e. :
Client Commands
Once the web client has connected (see JavaScript below) it sends a command ready to let the server know the connection is all set up correctly.
Drawing Commands
The data we need to send back to our client in order to draw the image consists of several commands :
- start : Tells the client we’re starting and provides the canvas size so the client can match it in the browser’s canvas
- clear : Clear the canvas completely
- x,y : The user drew a line to this point
- pointer_lifted : The user stopped drawing a line
Linking drawing events to the server
Because we’re looping indefinitely (for the duration of the connection) in the session context we need a way of getting data into the loop.
For this we have two queues (LinkedLists), one for commands and one for x,y points. We have functions that add items to end of the queue and, within the session loop, these are removed from the head of the queue and sent to the client.
(Because regular LinkedLists aren’t thread safe we use ConcurrentLinkedQueues instead)
This concludes the server part, now on to the client.
Client-side Implementation
The client-side code for this consists of a simple website with a HTML canvas and a box for entering the server IP address. This is linked to a JavaScript file which :
- Creates the WebSocket connection
- Listens to events and data (frames)
- Draws on the HTML Canvas
I won’t go into too much detail about this because it’s relatively basic.
The core concepts are outlined in the following code block but please check out the full code for the complete implementation :
That’s it, I hope it’s not too confusing! Comments, corrections and PRs welcome.