我在我的 java fx solitaire 应用程序上使用鼠标事件处理程序。它只是为桌面设计的。然后我发现了 JavaFx 端口。所以我尝试测试我的应用程序是否可以在移动设备上运行。它显示得很好,如下图所示。
我的问题是当我尝试拖放卡片时。它使应用程序崩溃。可能是因为我的事件处理?
我在真实设备(Kindle Fire)和VM(Blue Stacks)上尝试过以下是Blue Stacks VM的错误日志。
07-24 13:59:51.313 6441 6474 I System.out: don't add points, primary = -1
07-24 13:59:51.313 6441 6474 I System.out: Top Card: 9H
07-24 13:59:51.313 6441 6474 I System.out: Source Card: 8S
07-24 13:59:51.313 6441 6474 I System.out: createNewCard(): Creating card...
07-24 13:59:51.313 6441 6474 I System.out: createNewCard(): Setting card images...
07-24 13:59:51.333 6441 6474 I System.out: createNewCard(): Setting card name...
07-24 13:59:51.333 6441 6474 I System.out: createNewCard(): Setting card Event Filter...
07-24 13:59:51.333 6441 6474 I System.out: createNewCard(): Setting card location..
07-24 13:59:51.333 6441 6474 I System.out: createNewCard(): Setting card color...
07-24 13:59:51.333 6441 6474 I System.out: createNewCard(): Returning card...
07-24 13:59:51.333 1881 1963 D BstCommandProcessor-Application: Application crash has been observed.
07-24 13:59:51.333 6441 6474 I Process : Sending signal. PID: 6441 SIG: 9
07-24 13:59:51.333 6441 6474 D AndroidRuntime: procName from cmdline: com.gluonapplication2
07-24 13:59:51.333 6441 6474 E AndroidRuntime: in writeCrashedAppName, pkgName :com.gluonapplication2
07-24 13:59:51.333 6441 6474 D AndroidRuntime: file written successfully with content: com.gluonapplication2 StringBuffer : ;com.gluonapplication2
07-24 13:59:51.333 6441 6474 E AndroidRuntime: FATAL EXCEPTION: JavaFX Application Thread
07-24 13:59:51.333 6441 6474 E AndroidRuntime: Process: com.gluonapplication2, PID: 6441
07-24 13:59:51.333 6441 6474 E AndroidRuntime: java.lang.NoSuchMethodError: java.util.ArrayList.stream
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.gluonapplication2.views.SolitaireEvent.lambda$dragDropped$5(SolitaireEvent.java:142)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.gluonapplication2.views.SolitaireEvent.access$lambda$4(SolitaireEvent.java)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.gluonapplication2.views.SolitaireEvent$$Lambda$7.handle(Unknown Source)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at javafx.event.Event.fireEvent(Event.java:198)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at javafx.scene.Scene$DnDGesture.fireEvent(Scene.java:2937)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at javafx.scene.Scene$DnDGesture.processTargetDrop(Scene.java:3163)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at javafx.scene.Scene$DnDGesture.access$6400(Scene.java:2913)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at javafx.scene.Scene$DropTargetListener.drop(Scene.java:2877)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.tk.quantum.GlassSceneDnDEventHandler.lambda$handleDragDrop$291(GlassSceneDnDEventHandler.java:95)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.tk.quantum.GlassSceneDnDEventHandler.access$lambda$2(GlassSceneDnDEventHandler.java)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.tk.quantum.GlassSceneDnDEventHandler$$Lambda$3.run(Unknown Source)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at java.security.AccessController.doPrivileged(AccessController.java:52)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.tk.quantum.GlassSceneDnDEventHandler.handleDragDrop(GlassSceneDnDEventHandler.java:92)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleDragDrop$345(GlassViewEventHandler.java:672)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.tk.quantum.GlassViewEventHandler.access$lambda$7(GlassViewEventHandler.java)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$10.get(Unknown Source)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:391)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleDragDrop(GlassViewEventHandler.java:671)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.View.handleDragDrop(View.java:712)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.View.notifyDragDrop(View.java:1037)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.monocle.MonocleView.notifyDragDrop(MonocleView.java:163)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.monocle.MouseInput.notifyMouse(MouseInput.java:248)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.monocle.MouseInput.lambda$postMouseEvent$100(MouseInput.java:227)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.monocle.MouseInput.access$lambda$3(MouseInput.java)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.monocle.MouseInput$$Lambda$4.run(Unknown Source)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.monocle.RunnableProcessor.runLoop(RunnableProcessor.java:92)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.monocle.RunnableProcessor.enterNestedEventLoop(RunnableProcessor.java:107)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.monocle.MonocleApplication._enterNestedEventLoop(MonocleApplication.java:144)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.monocle.MonocleApplication.enterDnDEventLoop(MonocleApplication.java:371)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.monocle.MonocleDnDClipboard.pushToSystem(MonocleDnDClipboard.java:54)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.SystemClipboard.flush(SystemClipboard.java:51)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.glass.ui.ClipboardAssistance.flush(ClipboardAssistance.java:59)
07-24 13:59:51.333 6441 6474 E AndroidRuntime: at com.sun.java
07-24 13:59:51.343 1881 1963 W BstCommandProcessor-Application: in sendHttpRequest, requestType is of CRASH_APP type but one of the requiredInfo is NULL, crashedApp = com.bluestacks.BstCommandProcessor.BstCrashedAppInfo@4e79b1e8
07-24 13:59:51.343 1881 1963 D BstCommandProcessor-Application: in sendHttpRequest, request to send to (fqdn): http://10.0.2.2:2861/AppCrashedInfo
07-24 13:59:51.343 1881 1963 D BstCommandProcessor-Application: data: {"packageName":"com.gluonapplication2","shortPackageName":"com.gluonapplication2","versionCode":1,"versionName":"1.0"}
07-24 13:59:51.363 1677 1924 I ActivityManager: Process com.gluonapplication2 (pid 6441) has died.
07-24 13:59:51.363 1677 1880 I WindowState: WIN DEATH: Window{4e8b30d8 u0 com.gluonapplication2/javafxports.android.FXActivity}
07-24 13:59:51.363 1677 1924 W ActivityManager: Force removing ActivityRecord{4eaf8ee8 u0 com.gluonapplication2/javafxports.android.FXActivity t9}: app died, no saved state
这是我的 SolitaireEvent.Java 代码。我评论了错误日志告诉的第 142 行
public class SolitaireEvent {
Pane tempPane;
double locationY;
EventHandler mouseDrag;
DataFormat cardDataFormat;
AlertDialog alert;
static ArrayList<Card> cardList;
ArrayList<Pane> topPanes;
public SolitaireEvent(Pane tempPane, double locationY, EventHandler mouseDrag, DataFormat cardDataFormat) {
this.tempPane = tempPane;
this.locationY = locationY;
this.mouseDrag = mouseDrag;
this.cardDataFormat = cardDataFormat;
}
public SolitaireEvent(ArrayList<Pane> topPanes, Pane tempPane, double locationY, EventHandler mouseDrag, DataFormat cardDataFormat) {
this.topPanes = topPanes;
this.tempPane = tempPane;
this.locationY = locationY;
this.mouseDrag = mouseDrag;
this.cardDataFormat = cardDataFormat;
}
public SolitaireEvent(DataFormat cardDataFormat) {
this.cardDataFormat = cardDataFormat;
}
public void dragDetected(Object object) {
final Card card = (Card) object;
card.setOnDragDetected((MouseEvent event) -> {
// drag was detected, start drag-and-drop gesture
System.out.println("onDragDetected");
cardList = new ArrayList<>();
Dragboard db = card.startDragAndDrop(TransferMode.ANY);
for (int i = tempPane.getChildren().indexOf(card); i < tempPane.getChildren().size(); i++) {
Card cardMove = (Card) tempPane.getChildren().get(i);
System.out.println("cardList Source Pane: " + tempPane + " Source Card: " + cardMove.getName());
cardList.add(cardMove);
}
Image [] image = new Image[cardList.size()];
//db.setDragView(image);
// put a string on dragboard
ClipboardContent content = new ClipboardContent();
content.put(cardDataFormat, cardList);
db.setContent(content);
event.consume();
});
}
public void dragOver(Object e) {
//System.out.println("onDragOver");
Pane targetPane = (Pane) e;
targetPane.setOnDragOver((DragEvent event) -> {
// data is dragged over the target
// accept it only if it is not dragged from the same node
// and if it has a string data
if (event.getGestureSource() != targetPane
&& event.getDragboard().hasContent(cardDataFormat)) {
// allow for both copying and moving, whatever user chooses
event.acceptTransferModes(TransferMode.ANY);
}
event.consume();
});
}
public void dragEntered(Object e) {
Pane targetPane = (Pane) e;
targetPane.setOnDragEntered((DragEvent event) -> {
// the drag-and-drop gesture entered the target
System.out.println("onDragEntered");
// show to the user that it is an actual gesture target
if (event.getGestureSource() != targetPane && event.getDragboard().hasContent(cardDataFormat)) {
//targetPane.setBackground(new Background(new BackgroundFill(Color.GREEN, CornerRadii.EMPTY, Insets.EMPTY)));
}
event.consume();
});
}
public void dragExited(Object e) {
//System.out.println("onDragExited");
Pane target = (Pane) e;
target.setOnDragExited((DragEvent event) -> {
// mouse moved away, remove the graphical cues
// target.setBackground(new Background(new BackgroundFill(Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY)));
event.consume();
});
}
public void dragDropped(Object e) {
Pane targetPane = (Pane) e;
targetPane.setOnDragDropped((DragEvent event) -> {
// Get the Dragboard data
Dragboard db = event.getDragboard();
boolean success = false;
// if there is an image data on dragboard, read it and use it
if (db.hasContent(cardDataFormat)) {
Card targetTopCard = getTargetTopCard(targetPane);
ArrayList<Card> cardSourceList = (ArrayList<Card>) db.getContent(cardDataFormat);
if (checkCards(cardSourceList, targetPane, targetTopCard)) {
// Line 142 is the next line
cardList.stream().forEach((sourceCard) -> {
dragDone(sourceCard);
});
targetTopCard = null;
cardList = null;
}
}
// transferred and used
event.setDropCompleted(success);
event.consume();
});
}
private boolean checkCards(ArrayList<Card> cardSourceList, Pane targetPane, Card targetTopCard) {
boolean success = false;
SolitaireRule solRule = new SolitaireRule();
for (Card sourceCard : cardSourceList) {
if (!checkTopPanes(targetPane)) {
if (!targetPane.getChildren().isEmpty()) {
if (!solRule.sameColor(sourceCard.getName(), targetTopCard.getName())) {
if (solRule.compareRank(sourceCard.getName(), targetTopCard.getName())) {
locationY = getLocationY(targetPane);
Card card = createNewCard(sourceCard.getName());
targetPane.getChildren().add(card);
success = true;
} else {
//alert = new AlertDialog(Alert.AlertType.WARNING, "Warning", "Same Color", "The cards are the same colors.");
success = false;
break;
}
} else {
//alert = new AlertDialog(Alert.AlertType.WARNING, "Warning", "Same Color", "The cards are the same colors.");
success = false;
break;
}
} else {
success = acceptKing(targetTopCard, sourceCard, targetPane);
}
targetTopCard = sourceCard;
} else {
success = acceptAce(targetTopCard, sourceCard, targetPane);
break;
}
}
return success;
}
private boolean checkTopPanes(Pane targetPane) {
boolean found = false;
for (Pane pane : topPanes) {
if (pane == targetPane) {
found = true;
System.out.println("Found Pane: " + targetPane);
break;
}
}
return found;
}
public void dragDone(Card sourceCard) {
System.out.println("cardList Source Pane: " + tempPane + " cardList Source Card: " + sourceCard);
tempPane.getChildren().remove(sourceCard);
if (!tempPane.getChildren().isEmpty()) {
// Flip the last
new SolitaireAnimation().flipCard(tempPane, mouseDrag);
}
}
private Card createNewCard(String cardName) {
System.out.println("createNewCard(): Creating card...");
Card card = new Card();
System.out.println("createNewCard(): Setting card images...");
card.setImage(new Image(SolitaireEvent.class.getResourceAsStream("/" + cardName + card.IMGEXT)));
System.out.println("createNewCard(): Setting card name...");
card.setName(cardName);
System.out.println("createNewCard(): Setting card Event Filter...");
card.addEventFilter(MouseDragEvent.MOUSE_PRESSED, mouseDrag);
System.out.println("createNewCard(): Setting card location..");
card.setLayoutY(locationY);
System.out.println("createNewCard(): Setting card color...");
if (cardName.endsWith("H") || cardName.endsWith("D")) {
card.setIsRed(true);
} else if (cardName.endsWith("S") || cardName.endsWith("C")) {
card.setIsBlack(true);
}
System.out.println("createNewCard(): Returning card...");
return card;
}
private boolean acceptKing(Card topCard, Card sourceCard, Pane targetPane) {
boolean success = false;
Card card = new Card();
if (sourceCard.getName().substring(0, 1).equals("K")) {
System.out.println("acceptKing()[Accepted, this is a " + sourceCard.getName().substring(0, 1) + "]");
card = createNewCard(sourceCard.getName());
targetPane.getChildren().add(card);
success = true;
}
return success;
}
private boolean acceptAce(Card topCard, Card sourceCard, Pane targetPane) {
boolean success = false;
Card card = new Card();
if (targetPane.getChildren().isEmpty()) {
System.out.println("acceptAce()[Pane is empty]");
if (sourceCard.getName().substring(0, 1).equals("A")) {
System.out.println("acceptAce()[This is Ace]");
card = createNewCard(sourceCard.getName());
targetPane.getChildren().add(card);
success = true;
}
} else {
System.out.println("acceptAce()[Not Ace]");
SolitaireRule solRule = new SolitaireRule();
if (solRule.foundationRank(sourceCard.getName(), topCard.getName())) {
card = createNewCard(sourceCard.getName());
targetPane.getChildren().add(card);
success = true;
}
}
return success;
}
private double getLocationY(Pane targetPane) {
double returnLocation = 0.0;
double layoutY = 0.0;
// Get the y location and the last card of the last index
if (!tempPane.getChildren().isEmpty()) {
for (Node children : targetPane.getChildren()) {
layoutY = children.getLayoutY();
}
}
// Check if the target pane is empty, if true
// set the location of y to 0 else add 30
if (targetPane.getChildren().isEmpty()) {
returnLocation = 0;
} else if (targetPane == tempPane) {
returnLocation = layoutY;
} else {
returnLocation = layoutY + 30;
}
return returnLocation;
}
private Card getTargetTopCard(Pane targetPane) {
Card topCard = null;
// Get the y location and the last card of the last index
if (!tempPane.getChildren().isEmpty()) {
for (Node children : targetPane.getChildren()) {
topCard = (Card) children;
}
}
return topCard;
}
}