如何从 java 中的另一个 class 的事件侦听器中检索值?

How to retrieve the value from the event listener from another class in java?

我有一个程序可以从条形码扫描器(使用 jssc 库)获取值,它 returns 使用事件侦听器的预期值,但我需要从另一个 class 访问该值.

我尝试将 BarcodeScanner class 实例化到主要方法 (ProcessTicket class) 并调用 scannerHandler 方法,还调用模型 class 的 getter 方法来检索值但是 getter 方法在扫描完成之前运行。你能帮我实现这个目标吗?

    public class BarcodeScanner {
            public static Object SerialPortReader;
            static SerialPort serialPort;
         public void scannerHandler() {
                serialPort = new SerialPort("COM4");      
    try{
       serialPort.openPort();//Open serial port
      //Set params. Also set params by this string: 
       serialPort.setParams(9600, 8, 1, 0);
       serialPort.setParams(9600, 8, 1, 0);
       serialPort.writeString(new String(new byte[]{0x02})); //triggers barcode scanner
       serialPort.addEventListener(new SerialPortReader());//Add SerialPortEventListenerS
    } catch (SerialPortException ex) {
                    System.out.println(ex);
                }
            }

        public static class SerialPortReader implements SerialPortEventListener {
                String str;
                String value;

                public void serialEvent(SerialPortEvent event) {
                    if (event.isRXCHAR() && event.getEventValue() > 0) {//If data is available
                        //Check bytes count in the input buffer
                        try {
                            byte[] bytesCont = serialPort.readBytes(14);
                            str = new String(bytesCont);
                            ModelClass modelClass = new ModelClass();
                            modelClass.setBarcodeValue(str);
                        } catch (SerialPortException e) {
                            e.printStackTrace();
                        }
                    }
        }

我的ProcessTicket.javaClass

public class ProcessTicket {
    public static void main(String[] args) throws SQLException, SerialPortException {
 BarcodeScanner bSC = new BarcodeScanner();
        bSC.scannerHandler();
       BarcodeScanner.SerialPortReader portReader = new BarcodeScanner.SerialPortReader();
       ModelClass modelClass = new ModelClass();
       String value = modelClass.getBarcodeValue();
       System.out.println(value);
    }
}

这里的主要问题是您将固有的异步操作(从现实世界中的外部传感器读取)视为同步操作。

我模拟了外部传感器的东西来制作一个独立的应用程序来测试您的业务逻辑:

HowToRetrieveTheValueFromTheEventListenerFromAnotherClassInJava.java

package com.Whosebug;

/**
 * 
 */
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();
    }
}

调用 MockUser.startScanningStuffLol() 只是必要的,因为我只是在代码中测试它,没有使用真正的条形码扫描仪。请不要专注于此。如果你问,我会 post 它的实现,但除此之外,我假设你的 OS/Java/hardware 正在按照它们设计的方式工作,你可以用这些工具而不是我的 MockUser 软件模拟.

以下是实现此功能所需的其余 classes:

BarcodeScannedCallback.java

package com.Whosebug;

public interface BarcodeScannedCallback {

    void callback(String barcode);
}

由于我们处理的是异步操作,我们不能像处理同步操作那样只是启动它然后检查 return 值。相反,我们需要传入一个将在操作完成后调用的函数,然后等待它完成。 BarcodeScannedCallback 是该函数的签名(换句话说,描述该函数需要如何构建)。它接受一个字符串参数,return什么都没有。

BarcodeScannedCallback 的实现是我在上面提到的这个函数,我将其传递给 BarcodeScanner 构造函数:

(String barcode) -> {
    System.out.println("Barcode scanned: " + barcode);
}

如您所见,此函数采用一个字符串参数,return什么也没有。所以,它是 BarcodeScannedCallback 接口的实现。

现在是最后一个 class:使用上述接口桥接我们的 main 方法和串行端口的方法。

BarcodeScanner.java

package com.Whosebug;

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;
    }
}

下面是这些事件的完整生命周期:

  • 您创建了一个BarcodeScanner
  • 你告诉 BarcodeScanner,通过 BarcodeScannedCallback 的实现,你传递给它的构造函数,一旦它通过串行端口接收到条形码,运行 的代码是什么。
  • 您在 BarcodeScanner 上调用 startScan,它会打开串行端口并开始等待用户扫描条形码。
  • 用户扫描条形码。此数据通过串行端口传输。操作系统的 SerialPort 调用 BarcodeScanner.serialEvent.
  • 您的 serialEvent 实现会进行验证,从串行端口提取数据并将其从字节转换为字符串,然后调用一开始传入的 BarcodeScannedCallback 函数。

当我 运行 这个(我的 MockUser class 设置一个后台线程,每 3 秒 "scans" 一个条形码),我得到这个输出:

Barcode scanned: 420L0L
Barcode scanned: 007
Barcode scanned: 12345

在您的情况下,您应该能够使用现实世界中的条码扫描器扫描 3 个条码,并获得相同的结果。

请注意,您可能需要采取一些措施来防止 main 方法的线程过早结束,具体取决于您 运行 在其中执行此操作的上下文。

如果您在 Android 应用程序或 Web 服务器中 运行ning 它,这些框架将无限期地保持其主线程 运行ning,直到您终止 app/server.

但是,如果您 运行 将其作为自定义命令行应用程序(根据 main 方法的存在,您似乎正在这样做),您将在你决定杀死它之前,你需要做一些事情来让它活着。最简单的方法是在 main 方法的最后一行放置一个无限循环,例如 while (true);