java - метод возврата строки вызывается до того, как какое-либо значение будет присвоено строке
Мое приложение должно читать и писать на последовательный порт. Данные читаются в EventListener класса PortReader. Я хочу присвоить эти данные глобальной переменной String (private String sPortReaderString) для дальнейшего использования. Глобальная строковая переменная должна возвращать свое значение, используя метод getPortReader(), который просто возвращает строку sPortReaderString. В JFrame приложения я открываю соединение через последовательный порт, отправляю команду, для которой я автоматически получаю ответ от последовательного устройства, и отображаю этот ответный ответ в метке. Проблема в том, что метка всегда пуста, так как sPortReaderString, возвращаемая из getPortReader(), не имеет ничего назначенного ей. Я очень уверен, что sPortReaderString получает значение в EvenListener. Похоже, проблема заключается в том, что метод getPortReader() в JFrame вызывается до того, как какое-либо значение успеет присвоиться sPortReaderString. Пожалуйста, посмотрите на мой отупут и код ниже:
Вот вывод, который я получаю:
sPortReaderString: PortReader
Краткий пример portsMethod в JFrame:
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
}
}
Ниже приведен пример моего класса последовательного порта:
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) {
}
}
}
}
}
}
1 ответ
Это кажется довольно логичным для меня:
У вас есть первый метод обработки событий в EDT, который получает версию прошивки, а затем получает считыватель портов. Получение версии прошивки приводит к получению события в другом потоке (и, следовательно, параллельно с выполнением portsMethod()
в EDT).
Код обработки событий вызывает SwingUtilities.invokeAndWait()
, Таким образом, этот вызов ожидает завершения первого обработчика события methd, а затем добавляет полученную строку к 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);
}
}
});
}
Примечание: ваш код сложен для понимания главным образом потому, что ваши переменные и методы имеют неправильные имена.