2017-04-06 144 views
0

当我在LoginViewController类中调用登录方法时,我收到一个NullPointerException。我知道用户对象不是空的,因为它用toString打印出对象。我需要以某种方式在LoginView.fxml中注册Client和User类吗?我试图实现的是,当用户点击登录时,方法应该实例化一个新的Client,它将User对象发送给服务器。与(JavaFX)调用方法时的NullPointerException

异常

User: Username Password 
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException 
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774) 
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657) 
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) 
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) 
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49) 
    at javafx.event.Event.fireEvent(Event.java:198) 
    at javafx.scene.Node.fireEvent(Node.java:8411) 
    at javafx.scene.control.Button.fire(Button.java:185) 
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182) 
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96) 
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89) 
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218) 
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) 
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) 
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) 
    at javafx.event.Event.fireEvent(Event.java:198) 
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757) 
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485) 
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762) 
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416) 
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415) 
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555) 
    at com.sun.glass.ui.View.notifyMouse(View.java:937) 
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) 
    at java.lang.Thread.run(Unknown Source) 
Caused by: java.lang.reflect.InvocationTargetException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
    at java.lang.reflect.Method.invoke(Unknown Source) 
    at sun.reflect.misc.Trampoline.invoke(Unknown Source) 
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
    at java.lang.reflect.Method.invoke(Unknown Source) 
    at sun.reflect.misc.MethodUtil.invoke(Unknown Source) 
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1771) 
    ... 48 more 
Caused by: java.lang.NullPointerException 
    at dinnerTime.Client.sendToServer(Client.java:44) 
    at dinnerTime.LoginViewController.login(LoginViewController.java:34) 
    ... 58 more 

Main.java

package dinnerTime; 

import java.io.IOException; 
import javafx.application.Application; 
import javafx.fxml.FXML; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Scene; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 

public class Main extends Application { 
    private Stage primaryStage; 
    private BorderPane mainLayout; 

    public static void main(String[] args) { 
     launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     this.primaryStage = primaryStage; 
     showLoginView(); 
    } 

    private void showLoginView() throws IOException { 
     FXMLLoader loader = new FXMLLoader(); 
     loader.setLocation(Main.class.getResource("LoginView.fxml")); 
     mainLayout = loader.load(); 
     Scene scene = new Scene(mainLayout, 540, 400); 
     primaryStage.setScene(scene); 
     primaryStage.setResizable(false); 
     primaryStage.show(); 
    } 
} 

LoginViewController.java

package dinnerTime; 

import java.io.IOException; 
import java.net.URL; 
import java.util.ResourceBundle; 
import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.scene.control.Button; 
import javafx.scene.control.PasswordField; 
import javafx.scene.control.TextField; 

public class LoginViewController { 
    @FXML 
    private Main main; 
    @FXML 
    private TextField username; 
    @FXML 
    private PasswordField password; 
    @FXML 
    private Button login; 
    @FXML 
    private Button register; 

    private Client client; 

    private User user; 

    @FXML 
    public void login() throws IOException { 
     client = new Client("127.0.0.1", 3250); 
     client.start(); 
     user = new User(username.getText(), password.getText()); 
     System.out.println("User: " + user.toString()); 
     client.sendToServer(user); 
    } 
} 

LoginView.fxml

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.control.Button?> 
<?import javafx.scene.control.Label?> 
<?import javafx.scene.control.PasswordField?> 
<?import javafx.scene.control.TextField?> 
<?import javafx.scene.image.Image?> 
<?import javafx.scene.image.ImageView?> 
<?import javafx.scene.layout.AnchorPane?> 
<?import javafx.scene.layout.BorderPane?> 
<?import javafx.scene.text.Font?> 

<BorderPane prefHeight="400.0" prefWidth="540.0" xmlns="http://javafx.com/javafx/8.0.102" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dinnerTime.LoginViewController"> 
    <center> 
     <AnchorPane prefHeight="400.0" prefWidth="540.0" BorderPane.alignment="CENTER"> 
     <children> 
      <ImageView fitHeight="122.0" fitWidth="124.0" layoutX="238.0" layoutY="14.0" pickOnBounds="true" preserveRatio="true"> 
       <image> 
        <Image url="@../../images/dt-logo-original.png" /> 
       </image> 
      </ImageView> 
      <Label layoutX="14.0" layoutY="14.0" text="Dinner" textFill="#464646"> 
       <font> 
        <Font size="70.0" /> 
       </font> 
      </Label> 
      <Label layoutX="372.0" layoutY="14.0" text="Time" textFill="#464646"> 
       <font> 
        <Font size="70.0" /> 
       </font></Label> 
      <Label layoutX="91.0" layoutY="155.0" text="Username" /> 
      <TextField layoutX="164.0" layoutY="151.0" prefHeight="25.0" prefWidth="216.0" /> 
      <Label layoutX="91.0" layoutY="213.0" text="Password" /> 
      <PasswordField layoutX="164.0" layoutY="209.0" prefHeight="25.0" prefWidth="216.0" /> 
      <Button fx:id="login" layoutX="162.0" layoutY="271.0" mnemonicParsing="false" onAction="#login" prefHeight="59.0" prefWidth="216.0" text="Login" /> 
      <Button layoutX="242.0" layoutY="352.0" mnemonicParsing="false" text="Register" /> 
     </children> 
     </AnchorPane> 
    </center> 
</BorderPane> 

Client.java

package dinnerTime; 

import java.io.*; 
import java.net.*; 

public class Client extends Thread { 
    private String ip; 
    private int port; 
    private Socket socket; 
    private ObjectOutputStream oos; 
    private ObjectInputStream ois; 

    public Client(String ip, int port) { 
     this.ip = ip; 
     this.port = port; 
    } 

    public void run() { 
     try { 
      socket = new Socket(ip, port); 
      oos = new ObjectOutputStream(socket.getOutputStream()); 
      oos.flush(); 
      ois = new ObjectInputStream(socket.getInputStream()); 

      while (true) { 
       try { 
        Object obj = ois.readObject(); 

        if (obj instanceof Recipe) { 

        } 


       } catch (IOException | ClassNotFoundException e) { 
       } 
      } 
     } catch (IOException e) { 
     } 
    } 

    public void sendToServer(Object obj) { 
     try { 
      oos.writeObject(obj); 
      oos.flush(); 
     } catch (IOException e) { 
     } 
    } 
} 

User.java

package dinnerTime; 

import java.io.Serializable; 

public class User implements Serializable { 
    private String name, password; 

    public User(String name, String password){ 
     this.name = name; 
     this.password = password; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public String toString() { 
     return name + " " + password; 
    } 
} 
+1

你为什么注释'Client'和'User'与'@ FXML'?这些类不是节点,它们不包含在FXML文件中,也不包含在场景图中。 –

+0

我的不好,他们现在被删除。同样的例外。有任何想法吗? – Slamdunk

回答

0

你对客户的oos领域的race condition。在run()方法中初始化它,该方法在后台线程中执行,但您试图在sendToServer()中访问它,该控制器在控制器中从login()调用,并在FX应用程序线程上执行。

因为这些都是在不同的线程,也不能保证哪个将首先被执行:正在发生的事情是,后台线程初始化oos之前,因此oos.writeObject(...)抛出一个空指针异常sendToServer()是越来越执行。

要解决此问题,您需要确保在客户端完全连接之前不要致电sendToServer()。一种方法是提供某种形式的回调时建立的连接,执行:

public class Client extends Thread { 
    private String ip; 
    private int port; 
    private Socket socket; 
    private ObjectOutputStream oos; 
    private ObjectInputStream ois; 

    private Runnable onConnected ; 

    public void setOnConnected(Runnable onConnected) { 
     this.onConnected = onConnected ; 
    } 

    public Client(String ip, int port) { 
     this.ip = ip; 
     this.port = port; 
    } 

    public void run() { 
     try { 
      socket = new Socket(ip, port); 
      oos = new ObjectOutputStream(socket.getOutputStream()); 
      oos.flush(); 

      if (onConnected != null) { 
       onConnected.run(); 
      } 

      ois = new ObjectInputStream(socket.getInputStream()); 

      while (true) { 
       try { 
        Object obj = ois.readObject(); 

        if (obj instanceof Recipe) { 

        } 


       } catch (IOException | ClassNotFoundException e) { 
       } 
      } 
     } catch (IOException e) { 
     } 
    } 

    public void sendToServer(Object obj) { 
     try { 
      oos.writeObject(obj); 
      oos.flush(); 
     } catch (IOException e) { 
     } 
    } 
} 

然后

@FXML 
public void login() throws IOException { 
    client = new Client("127.0.0.1", 3250); 
    user = new User(username.getText(), password.getText()); 
    client.setOnConnected(() -> client.sendToServer(user)); 
    client.start(); 
} 
相关问题