【问题标题】:java - string return method is called before any value is assigned to stringjava - 在将任何值分配给字符串之前调用字符串返回方法
【发布时间】:2012-02-29 20:13:03
【问题描述】:

我的应用程序应该读取和写入串行端口。数据在 PortReader 类的 EventListener 中读取。我希望将此数据分配给全局字符串变量(私有字符串 sPortReaderString)以供进一步使用。全局字符串变量应使用名为 getPortReader() 的方法返回其值,该方法仅返回字符串 sPortReaderString。在应用程序的 JFrame 中,我打开串行端口连接,发送一个命令,我会自动收到来自串行设备的回复,并在标签中显示该回复输出。问题是标签始终为空白,因为从 getPortReader() 返回的 sPortReaderString 没有分配任何内容。我非常确定 sPortReaderString 在 EvenListener 中被分配了一个值。问题似乎是在任何值有足够的时间分配给 sPortReaderString 之前调用 JFrame 中的方法 getPortReader()。请看一下我的 otuput 和下面的代码:

以下是我得到的输出:

sPortReaderString:
PortReader

JFrame 中 portsMethod 的简短示例:

public class MyJFrame extends javax.swing.JFrame {

    public MySerialPort msp = new MySerialPort();   

    public MainJFrame() {
        portsMethod();
    }

    private void portsMethod() {

        msp.getPortNames();//Gets the name of the port (COM1 in my case)
        msp.openPort();//Opens COM1 port
        msp.getFirmwareVersion();//Prompts for device firmware version by sending a string command
        msp.getPortReader();//Reads the reply from device

    }

}

以下是我的 Serial Port 类的示例:

public class MySerialPort {

    private SerialPort serialPort;
    private int iBaudRate = SerialPort.BAUDRATE_57600;
    private int iDataBits = SerialPort.DATABITS_8;
    private int iStopBits = SerialPort.STOPBITS_1;
    private int iParity = SerialPort.PARITY_NONE;
    private String sPortName;
    private String sPortReaderString = "";
    private StringBuilder sbPortReaderString = new StringBuilder();

    public void getFirmwareVersion() {
        sendPortCommand("<FirmVer>\r\n");
    }

    public void clearPortReader() {
        sbPortReaderString.setLength(0);
    }

    public String getPortReader() {
        System.out.print("sPortReaderString: " + sPortReaderString);
        return sPortReaderString;
    }

    public void getPortNames() {
        String[] sPorts = SerialPortList.getPortNames();
        sPortName = sPorts[0];
    }

    public void openPort() {

        serialPort = new SerialPort(sPortName);

        try {

            if (serialPort.openPort()) {

                if (serialPort.setParams(iBaudRate, iDataBits, iStopBits, iParity)) {

                    serialPort.addEventListener(new PortReader(), SerialPort.MASK_RXCHAR
                            | SerialPort.MASK_RXFLAG
                            | SerialPort.MASK_CTS
                            | SerialPort.MASK_DSR
                            | SerialPort.MASK_RLSD);

                } else {
                    serialPort.closePort();
                }

            } else {}
        } catch (SerialPortException | HeadlessException ex) {}
    }

    private void sendPortCommand(String sSendPortCommand) {

        if (sSendPortCommand.length() > 0) {
            try {
                serialPort.writeBytes(sSendPortCommand.getBytes());
            } catch (Exception ex) {}
        }
    }

    private class PortReader implements SerialPortEventListener {

        private String sBuffer = "";

        @Override
        public void serialEvent(SerialPortEvent spe) {

            if (spe.isRXCHAR() || spe.isRXFLAG()) {

                if (spe.getEventValue() > 0) {

                    try {

                        //Read chars from buffer
                        byte[] bBuffer = serialPort.readBytes(spe.getEventValue());
                        sBuffer = new String(bBuffer);

                        SwingUtilities.invokeAndWait(
                                new Runnable() {

                                    @Override
                                    public void run() {
                                        sbPortReaderString.append(sBuffer);
                                    }
                                });

                        sPortReaderString = new String(sbPortReaderString);
               //if I print sPortReaderString in here it is not blank and has the correct value

                        System.out.print("PortReader");

                    } catch (SerialPortException | InterruptedException | InvocationTargetException ex) {
                    }
                }
            }
        }
    }
}

【问题讨论】:

  • 您至少应该打印或记录您的异常。您在几个可能掩盖错误的地方捕获和丢弃异常。
  • 为了缩短演示代码,我去掉了异常。我没有收到任何错误异常。
  • 您是否尝试过将您的sPortReaderString 设为volatile?是否被多个线程访问?
  • 你说msp.getPortReader();//Reads the reply from device不是这样的。如果只打印读取的内容。你确定在你拨打这个电话时它已经被阅读了吗?
  • @Gray - 是的,我尝试让我的 sPortReaderString 易失。在 jframe 的方法中,我认为我没有任何线程。

标签: java multithreading string swingutilities invokeandwait


【解决方案1】:

对我来说这似乎很合乎逻辑:

您在 EDT 中执行了第一个事件处理方法,该方法获取固件版本,然后获取端口读取器。获取固件版本会导致接收事件,在不同的线程中(因此与 EDT 中 portsMethod() 的执行并行)。

事件处理代码调用SwingUtilities.invokeAndWait()。因此,此调用等待第一个事件处理方法完成,然后将接收到的字符串附加到sbPortReaderString。因此,此附加是在 portsMethod 完成后完成的。

串行端口提供基于事件的机制。我会简单地使用它将事件传播到 EDT 中的一个或多个侦听器:

// accessed only from the EDT
private List<MyPortListener> portListeners = new ArrayList<MyPortListener>();

public void addMyPortListener(MyPortListener listener) {
    portListeners.add(listener);
}

public void removeMyPortListener(MyPortListener listener) {
    portListeners.remove(listener);
}

... 

    @Override
    public void serialEvent(SerialPortEvent spe) {
        ...
        final String receivedString = ...;
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                for (MyPortListener listener : portListeners) {
                    listener.stringReveivedFromSerialPort(receivedString);
                }
            }
        });
    }

旁注:您的代码难以理解,主要是因为您的变量和方法命名错误。

【讨论】:

  • 非常感谢,您能指导我看一个简短的例子来说明我将如何做到这一点吗?我从来没有做过类似的事情。
  • 还有一个问题,先生。 MyPortListener 来自哪里?谢谢
  • 你定义它。这是一个只有一种方法的接口:void stringReveivedFromSerialPort(String)
  • 感谢您的耐心等待...由于我是初学者,请您说得更具体一些。通过接口,你是指一个类(比如我的 JFrame)还是......?再次非常感谢您
  • 接口是 Java 的核心概念,在 Swing 中无处不在。见docs.oracle.com/javase/tutorial/java/concepts/interface.html
猜你喜欢
  • 1970-01-01
  • 2014-01-16
  • 2011-01-16
  • 1970-01-01
  • 2020-01-22
  • 2013-05-04
  • 1970-01-01
  • 1970-01-01
  • 2015-03-15
相关资源
最近更新 更多