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

Java 8 如何从java中的另一个类中从事件侦听器检索值?,java-8,event-listener,jssc,Java 8,Event Listener,Jssc,我有一个程序从条形码扫描仪(使用jssc库)获取值,它使用事件侦听器按预期返回值,但我需要从另一个类访问该值 我尝试将BarcodeScanner类实例化为main方法(ProcessTicket类),并调用scannerHandler方法,还调用model类的getter方法来检索值,但getter方法在扫描完成之前运行。你能帮我做到这一点吗 public class BarcodeScanner { public static Object SerialPor

我有一个程序从条形码扫描仪(使用jssc库)获取值,它使用事件侦听器按预期返回值,但我需要从另一个类访问该值

我尝试将BarcodeScanner类实例化为main方法(ProcessTicket类),并调用scannerHandler方法,还调用model类的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.java类

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

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

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

如何从另一个Classinjava.java中从EventListener中检索值

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();
    }
}
package com.stackoverflow;

public interface BarcodeScannedCallback {

    void callback(String barcode);
}
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;
    }
}
调用
MockUser.startScanningStuffLol()
是必要的,因为我只是在代码中测试,没有使用真正的条形码扫描仪。请不要专注于它。如果你要求的话,我会发布它的实现,但是我假设你的OS/Java/硬件按照设计的方式工作,你可以用这些工具而不是我的
MockUser
软件模拟来测试它

以下是实现此功能所需的其他类:

BarcodeScannedCallback.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();
    }
}
package com.stackoverflow;

public interface BarcodeScannedCallback {

    void callback(String barcode);
}
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;
    }
}
因为我们处理的是一个异步操作,我们不能像同步操作那样启动它然后检查返回值。相反,我们需要传入一个函数,该函数将在操作完成后被调用,然后等待它完成
BarcodeScannedCallback
是该函数的签名(换句话说,描述该函数需要如何构造)。它只接受一个字符串参数,不返回任何内容

BarcodeScannedCallback
的实现就是我前面提到的这个函数,我将它传递到
BarcodeScanner
构造函数中:

(String barcode) -> {
    System.out.println("Barcode scanned: " + barcode);
}
如您所见,此函数接受一个字符串参数,但不返回任何内容。因此,它是
BarcodeScannedCallback
接口的实现

现在来看最后一个类:使用上面的接口连接我们的
main
方法和串行端口的类

BarcodeScanner.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();
    }
}
package com.stackoverflow;

public interface BarcodeScannedCallback {

    void callback(String barcode);
}
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;
    }
}
下面是这些事件的整个生命周期:

  • 您可以创建
    条形码扫描仪
  • 通过将
    BarcodeScannedCallback
    的实现传递到其构造函数中,告诉
    BarcodeScanner
    ,一旦它通过串行端口接收到条形码,将运行什么代码
  • 条形码扫描仪上调用
    startScan
    ,打开串行端口并开始等待用户扫描条形码
  • 用户扫描条形码。该数据通过串行端口传输。操作系统实现的
    SerialPort
    调用
    BarcodeScanner.serialEvent
  • serialEvent
    的实现执行验证,从串行端口提取数据并将其从字节转换为字符串,并调用开始时传入的
    BarcodeScannedCallback
    函数
当我运行此命令时(我的
MockUser
类设置了一个后台线程,每3秒“扫描”一次条形码),我得到以下输出:

Barcode scanned: 420L0L
Barcode scanned: 007
Barcode scanned: 12345
在您的情况下,您应该能够使用真实世界的条形码扫描仪扫描3个条形码,并获得相同的结果

请注意,您可能需要做一些事情来防止
main
方法的线程过早结束,这取决于您运行该方法的上下文

如果您在Android应用程序或web服务器上运行它,这些框架将无限期地保持其主线程运行,直到您杀死应用程序/服务器


但是,如果您将其作为自定义命令行应用程序运行(基于
main
方法的存在,您似乎正在这样做),那么您需要做一些事情来保持它的活力,直到您决定杀死它为止。最简单的方法是放置一个无限循环,如
while(true)
main
方法的最后一行。

在侦听器中创建一个返回所需内容的方法。当您在变量中创建侦听器对象并调用该方法时,请将其存储起来。您有一个“catch”,没有“try”。在开始考虑运行时错误之前,至少应该先编译代码。同样奇怪的是,一旦从端口读取,就会将结果放入这个“ModelClass”对象中,然后立即丢弃它,因为它是一个局部变量,并且方法结束。你希望它做什么?谢谢你的意见。我忘记粘贴try块,并在ProcessTicket上添加modelclass@Rogue如何在侦听器中创建方法?你能给我举个小例子吗。我仍然对event和actionlisteners很熟悉,就像任何其他类中的其他方法一样
public int getMyInt(){return 42;}
。你想用什么方法都行,这是你的课。有关通用OOP编程的参考。具体到这个问题,请参阅“类和对象”部分。非常感谢您的详细解释。它正在按预期工作。我正在使用Javafx创建一个应用程序。当按下按钮并根据条形码从数据库中提取数据时,应触发条形码。