2017-04-06 138 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(); 
} 
相關問題