The main problem here is that you're treating an inherently asynchronous operation (reading from an external sensor in the real world) as if it's synchronous.
I simulated that external sensor stuff to make a standalone app that tests your business logic:
HowToRetrieveTheValueFromTheEventListenerFromAnotherClassInJava.java
package com.stackoverflow;
/**
* https://stackoverflow.com/questions/57452205/how-to-retrieve-the-value-from-the-event-listener-from-another-class-in-java
*/
public class HowToRetrieveTheValueFromTheEventListenerFromAnotherClassInJava {
public static void main(String[] args) {
BarcodeScanner barcodeScanner = new BarcodeScanner((String barcode) -> {
System.out.println("Barcode scanned: " + barcode);
});
barcodeScanner.startScan();
MockUser.startScanningStuffLol();
}
}
That call to MockUser.startScanningStuffLol()
is only necessary because I'm testing this just in code, without using a real barcode scanner. Please don't focus on it. I'll post its implementation if you ask, but otherwise I'm assuming that your OS/Java/hardware are working the way they were designed to work, and you can just test this with those tools instead of my MockUser
software simulation.
Here are the rest of the classes that you need to implement this:
BarcodeScannedCallback.java
package com.stackoverflow;
public interface BarcodeScannedCallback {
void callback(String barcode);
}
Since we're dealing with an asynchronous operation, we can't just start it and then check for a return value, like we would with a synchronous operation. Instead, we need to pass in a function that will be called once the operation is complete, and just wait for it to finish. BarcodeScannedCallback
is the signature of that function (in other words, a description of how that function needs to be structured). It takes one string parameter, and returns nothing.
The implementation of BarcodeScannedCallback
is this function that I've already mentioned above, which I'm passing into the BarcodeScanner
constructor:
(String barcode) -> {
System.out.println("Barcode scanned: " + barcode);
}
As you can see, this function takes one string parameter, and returns nothing. So, it's an implementation of the BarcodeScannedCallback
interface.
Now for the last class: the one that bridges our main
method and the serial port, using the above interface.
BarcodeScanner.java
package com.stackoverflow;
public class BarcodeScanner implements SerialPortEventListener {
private SerialPort serialPort;
private final BarcodeScannedCallback callback;
public void startScan() {
try {
serialPort = new SerialPort("COM4");
serialPort.openPort();
serialPort.addEventListener(this);
// Also you can set params by this string: serialPort.setParams(9600, 8, 1, 0);
serialPort.setParams(9600, 8, 1, 0);
// Triggers barcode scanner.
serialPort.writeString(new String(new byte[]{0x02}));
} catch (SerialPortException ex) {
System.out.println(ex);
}
}
@Override
public void serialEvent(SerialPortEvent event) {
boolean isDataAvailable = event.isRXCHAR() && event.getEventValue() > 0;
if (isDataAvailable) {
try {
byte[] bytesCont = serialPort.readBytes(14);
String barcode = new String(bytesCont);
callback.callback(barcode);
} catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
public BarcodeScanner(BarcodeScannedCallback callback) {
this.callback = callback;
}
}
So here's the full lifecycle of these events:
- You create a
BarcodeScanner
.
- You tell the
BarcodeScanner
, via the implementation of BarcodeScannedCallback
that you pass into its constructor, what code to run once it receives a barcode over the serial port.
- You call
startScan
on the BarcodeScanner
, which opens the serial port and starts waiting for the user to scan a barcode.
- The user scans a barcode. This data is transmitted over the serial port. The operating system's implementation of
SerialPort
calls BarcodeScanner.serialEvent
.
- Your implementation of
serialEvent
does its validations, pulls the data from the serial port and converts it from bytes to a string, and calls the BarcodeScannedCallback
function that was passed in at the beginning.
When I run this (with my MockUser
class setting up a background thread that "scans" a barcode every 3 seconds), I get this output:
Barcode scanned: 420L0L
Barcode scanned: 007
Barcode scanned: 12345
In your case, you should be able to scan 3 barcodes with your real-world barcode scanner, and get the same results.
Note that you may need to do something to keep the main
method's thread from ending prematurely, depending on the context that you're running this in.
If you're running it in an Android app or a web server, those frameworks keep their main thread running indefinitely, until you kill the app/server.
But if you're running it as a custom command-line app (which it seems like you're doing, based on the existence of a main
method), you will need to do something to keep it alive until you decide to kill it. The simplest way is to put an infinite loop like while (true);
on the last line of your main
method.