Hello, everyone! This is my first blog, I hope you all enjoy it. After all, engineers are great problem solvers, right? We are expected to provide the finest & flexible solution for whatever situation exists. So I’ll be discussing how we solved the difficulty of handling multiple threads in our React-Native App, and how we accomplished it by providing a better approach.
Before we jump into the feature explanation part, let me give a quick glimpse of the project we worked on. It is a Healthcare Research project that helps the Cognitive Analysis Researchers/ Practitioners to observe, collect and store Brain Wave Pattern data of the Users, who are kids aged between 5 to 10 in the CSV format.
Recognizing the issue
Okay, I can understand your curiosity about what the problem is. So, for a better understanding, let me describe our app’s features that must be acknowledged. Our app is pretty intricate where every data in milliseconds is crucial and we need to collect the data and process it accordingly as per the client’s requirement.
Our initial objective was to collect data from the user by tapping the screen that was displayed to them. Humans have a response time of 0.25 seconds on average. Surprising right?
The above table shows the sample data acquired in milliseconds depending on a user’s tap on the screen, and we’ll need to collect comparable information based on the user’s answers.
To explain further,
The method we used to get the optimal solution:
There are several solutions to fix a problem, but selecting the best one might be difficult, here is one of the approaches that we considered applying to our app.
- Third-party library: The first thing I did was look for some third-party libraries in React Native for multithreading. I know you’re laughing, but it’s all about time, and working smart is preferable to working hard. Finally, we found a suitable library called react-native-multithreading, one of the best third-party libraries we have in react native.
- Challenge: Although it is an excellent library, there will always be a tiny overhead when calling spawnThread since all external variables must first be transferred into the new thread. If you utilize the separate thread to do sophisticated array operations, for example, we must remember that the array must first be copied into the separate thread. Which will result in performance differences.
Additionally, we must start and stop the data we are generating from the Arduino device as each game starts and sends, making this process expensive. According to our findings, when you run a lot of processes, performance suffers. As a result, we devised a plan to create a Native module.
We were scanning and connecting the Bluetooth device with a package called react-native-ble-manager, which made things a lot easier, and we started implementing the code in native Java inside the node module of the package the android.
What are Native Modules in React Native?
Before we can communicate with a BLE device, we must first understand the fundamental notions of BLE that are mentioned below.
- BLE- What is that? Bluetooth Low Energy (BLE) is a subset of Bluetooth’s 2.4 GHz wireless technology that focuses on low power and infrequent data exchanges for connected devices.
- Client / Central: A device that searches for and connects to Bluetooth Low Energy (BLE) peripherals in order to accomplish a task. This is usually an Android smartphone in the context of app development.
- Peripheral: A device that broadcasts its presence and is linked to a client/ central in order to perform a task. In the context of app development, this is usually a BLE device, such as a heart rate monitor. In our case, it’s our Arduino device.
- GATT Service: A set of characteristics (data fields) that describes a feature of a device, such as Device Information Service, which can have a characteristic indicating the device’s serial number and another reflecting the device’s battery level.
- GATT Characteristic: An entity containing meaningful data that can typically be read from or written to, e.g. the Serial Number String characteristic.
The term communication here means, Reading and Writing the data so we need to get the service with the characteristics to read and write the data. From our app, we would do both operations.
- Read: The client (app) reads the value of a characteristic or descriptor on the server / peripheral (BLE device) and interprets it based upon a protocol that has been established beforehand. For example, a smart thermostat may have a character whose value represents the current target temperature.
- Write: The client (app) writes some bytes to a characteristic or descriptor on the server / peripheral (BLE device). The server’s firmware processes the write and performs some server-side operations in response to it. For example, a smart thermostat may have a characteristic that changes the target temperature when written to.
So, in order to get data from the peripheral, we must first write some bytes to the peripheral’s characteristics. To do so, we must first check for the characteristic to which the byte has to be sent.
The preceding Embedded C code, which has been installed in our peripheral, shows that eventChar has a BLEWrite action, and this is the characteristic where we will write from our client / central (App).
The above image is the logic we came up with for starting and stopping data from the peripheral using native modules, which will be done for each tap by the user in the mobile application. When we trigger a stop, the written CSV data will be saved on the mobile’s internal storage and then finally to firebase DB.
This is how we overcame the difficulties faced in handling multiple threads in our app. Hope this blog helps to solve your discrepancies too.
In the next part, we’ll look at how the logic is implemented in native Java and Objective-C. 🤓