首页 文章

如何在Android上运行JavaFX

提问于
浏览
15

我尝试在Android上运行一个简单的JavaFX应用程序 . 因此,我使用gradle来阅读javafxports Getting Started Guide以构建应用程序,但我被困在某个地方 . 我可以在Eclipse中使用gradle的 installDebug 任务在Android设备上构建和安装应用程序,但是,当我启动应用程序时,我得到一个黑屏 . 当我提取 .apk 文件时,它不包含JavaFX应用程序的jar文件 . 我假设apk应该包含JavaFX应用程序jar文件,但我不知道如何将它包含在_1323973中 .

我还尝试使用gradle来构建JavaFX应用程序本身(jar文件),这很好 . 但是,我没有把它放到 dist 目录中,但我认为这只会在Netbeans中使用吗?我正在使用Eclipse gradle集成来构建项目 .

这是我试过的 . 由于JavaFX应用程序就像HelloWorld示例应用程序一样简单,并且像魅力一样工作,我希望在我的gradle构建文件中出现配置错误 .

build.gradle - to build the apk

apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'android'

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:2.5.0'
        classpath 'com.android.tools.build:gradle:1.0.1'
    }
}
repositories {
    jcenter()
}
ext {
    dalvikSdkHome = getProjectProperty('dalvikSDK')
    dalvikSdkLib = dalvikSdkHome + '/rt/lib'
}

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.1"
    dexOptions {
        preDexLibraries = false
    }
    sourceSets {
        main {
            jniLibs.srcDir file("${dalvikSdkLib}/")
            assets.srcDirs = ['assets']
        }
    }
    lintOptions {
        abortOnError false
    }
}

dependencies {
    compile files ("${dalvikSdkLib}/ext/jfxrt.jar",
                   "${dalvikSdkLib}/ext/jfxdvk.jar",
                   "${dalvikSdkLib}/ext/compat-1.0.0.jar")
}

project.tasks.withType(com.android.build.gradle.tasks.Dex) {
    additionalParameters=['--core-library']
}

String getProjectProperty(String propertyName) {
    project.hasProperty(propertyName) ? project.property(propertyName) : null
}

build.gradle - to build the jar

// Declares binary plugin and its required JavaFX classpath
apply from: "http://dl.bintray.com/content/shemnon/javafx-gradle/0.4.0/javafx.plugin"

// Configures plugin
javafx {
    // Points to JDK and its JavaFX libraries, also declares target runtime JDK
    javaRuntime = getProjectProperty('javaJDKPath')

    // Application name and ID presented by target OS
    appID 'HelloWorldApp'
    appName 'Hello World Application'

    // Main class of application
    mainClass 'helloworld.HelloWorld'

    // JVM arguments, system properties, application command line arguments
    jvmArgs = ['-XX:+AggressiveOpts', '-XX:CompileThreshold=1']
    systemProperties = ['prism.disableRegionCaching':'true']
    arguments = ['-l', '--fast']

    // Keystore credentials for signing JAR
    // Generate key: keytool -genkey -alias release -keyalg RSA -keystore keystore.jks -keysize 2048
    releaseKey {
        alias = 'release'
        keyStore = file(getProjectProperty('keystoreJKSFile')) // keyStore = file("${System.properties['user.home']}/keystore/keystore.jks")
        keyPass = getProjectProperty('keyStorePassword')
        storePass = getProjectProperty('storePassword')
    }

    signingMode 'release'
    // ...
}

String getProjectProperty(String propertyName) {
    project.hasProperty(propertyName) ? project.property(propertyName) : null
}

gradle.properties

javaJDKPath=D:/Java/jdk1.8.0_20
dalvikSDK=D:/Java/dalvik-sdk-8u20b3/dalvik-sdk
keystoreJKSFile=D:/Java/jre1.8.0_20/bin/keystore.jks
keyStorePassword=password
storePassword=password

local.properties

sdk.dir=D:/programme/Android/adt-bundle-windows-x86_64-20130917/sdk

And this is my project structure

HelloWorld
-- src\main
    -- java\helloworld\HelloWorld.java
    -- res\
    -- AndroidManifest.xml
-- assets\
    -- javafx.platform.properties
    -- javafx.properties
-- build.gradle
-- gradle.properties
-- local.properties

我需要使用 dist 目录吗?我将把我的JavaFX应用程序的jar文件放在哪里将它包含在apk文件中?

2 回答

  • 9

    现在回答我自己的问题 . 我的问题中发布的gradle设置配置已经在运行 . 在我的问题中,我没有告诉你我正在使用.fxml文件进行布局 . 所以我没有让它运行的原因是因为.fxml布局没有被放置在与apk文件一起打包的正确位置(LogCat显示错误 Location Not Found 并且我的设备上有黑屏) .

    首先, here is a working sample for the HelloWorld.java (参见我的问题中的结构和gradle设置等):

    package helloworld;
    
    import javafx.application.Application;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class HelloWorld extends Application {
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage primaryStage) {
            primaryStage.setTitle("Hello World!");
            Button btn = new Button();
            btn.setText("Say 'Hello World'");
            btn.setOnAction(new EventHandler<ActionEvent>() {
    
                @Override
                public void handle(ActionEvent event) {
                    System.out.println("Hello World!");
                }
            });
    
            StackPane root = new StackPane();
            root.getChildren().add(btn);
            primaryStage.setScene(new Scene(root, 300, 250));
            primaryStage.show();
        }
    }
    

    使用fxml布局在Android上运行JavaFX

    如果您想使用 .fxml 文件,则需要稍微更改项目的结构 . 所有 .fxml 文件, .css 文件,图形等都属于 resources\assets 目录或子目录 . 这可以确保.fxml文件等将打包在apk中 .

    HelloWorld
    -- src\main
        -- java\helloworld\
            -- HelloWorld.java
            -- MyController.java
        -- resources\assets\
            -- sample_layout.fxml
        -- AndroidManifest.xml
    -- assets\
        -- javafx.platform.properties
        -- javafx.properties
    -- build.gradle
    -- gradle.properties
    -- local.properties
    

    我没有检查,是否仍然需要包含 javafx.platform.propertiesjavafx.properties (均来自dalvikVM sdk)的 assets 文件夹 . 如果我检查.apk文件的内容,则apk包含两个文件 . 好像dalvikVM库会自动复制这些文件 .

    注意:如果你需要检查你的apk的内容,提取apk文件,然后提取classes.dex这是apk的一部分(see this post for more details

    Here is an example using .fxml files:

    HelloWorld.java

    package helloworld;
    
    import java.io.IOException;
    import java.net.URL;
    
    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.fxml.FXMLLoader;
    import javafx.stage.Stage;
    import javafx.scene.Scene;
    import javafx.scene.layout.AnchorPane;
    
    public class HelloWorld extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage primaryStage) {
            try {
                URL fxmlFile = getClass().getResource("/assets/sample_layout.fxml");
                FXMLLoader loader = new FXMLLoader(fxmlFile);
                AnchorPane page = (AnchorPane) loader.load();
                MyController controller = (MyController) loader.getController();
                Scene scene = new Scene(page);
                primaryStage.setScene(scene);
                primaryStage.setTitle("JavaFX Sample");
                primaryStage.show();
            } catch(IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    

    MyController.java

    package helloworld;
    
    import java.net.URL;
    import java.util.ResourceBundle;
    
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    
    public class MyController {
    
        @FXML
        private ResourceBundle resources;
        @FXML
        private URL location;
        @FXML
        private Label label_Counter;
        @FXML
        private Button button_IncrementCounter;
        @FXML
        private Button button_DecrementCounter;
    
        private static final String OUTPUT_PREFIX = "Counter: ";
        private static int counter = 0;
    
        @FXML
        void onIncrementButtonPressed(ActionEvent event) {
            label_Counter.setText(OUTPUT_PREFIX + ++counter);
        }
    
        @FXML
        void onDecrementButtonPressed(ActionEvent event) {
            label_Counter.setText(OUTPUT_PREFIX + --counter);
        }
    
        @FXML
        void initialize() {
            assert label_Counter != null : "fx:id=\"label_Counter\" was not injected: check your FXML file 'sample_layout.fxml'.";
            assert button_IncrementCounter != null : "fx:id=\"button_IncrementCounter\" was not injected: check your FXML file 'sample_layout.fxml'.";
            assert button_DecrementCounter != null : "fx:id=\"button_DecrementCounter\" was not injected: check your FXML file 'sample_layout.fxml'.";
            label_Counter.setText(OUTPUT_PREFIX + 0);
        }
    
    }
    

    sample_layout.fxml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.geometry.*?>
    <?import javafx.scene.control.*?>
    <?import java.lang.*?>
    <?import javafx.scene.layout.*?>
    
    <AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="helloworld.MyController">
       <children>
          <VBox layoutX="332.0" layoutY="71.0" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
             <children>
                <Label text="Please click on the buttons to increment or decrement the counter:" />
                <Button fx:id="button_IncrementCounter" mnemonicParsing="false" onAction="#onIncrementButtonPressed" text="Increment Counter">
                   <VBox.margin>
                      <Insets top="10.0" />
                   </VBox.margin>
                   <padding>
                      <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
                   </padding>
                </Button>
                <Button fx:id="button_DecrementCounter" mnemonicParsing="false" onAction="#onDecrementButtonPressed" text="Decrement Counter">
                   <VBox.margin>
                      <Insets top="10.0" />
                   </VBox.margin>
                   <padding>
                      <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
                   </padding>
                </Button>
                <Label fx:id="label_Counter" text="&lt;output-placeholder&gt;">
                   <VBox.margin>
                      <Insets top="20.0" />
                   </VBox.margin>
                </Label>
             </children>
             <padding>
                <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
             </padding>
          </VBox>
       </children>
    </AnchorPane>
    

    希望能帮助其他人在Android上开始使用JavaFX .

  • 2

    如何在android上运行javafx:

    • 下载dalvik sdk .

    • 转到 samples\HelloWorld\javafx - 这是gradle项目

    • 修改 local.properties 中dalvik-sdk和android-sdk的位置
      我的Windows系统上的示例:
      sdk.dir=C\:\\dev\\android-sdk javafx.dir=C\:\\dev\\dalvik-sdk

    • 运行 gradlew installDebug 用于在设备上构建和安装apk . 您还可以在 build 文件夹中找到输出

    • 在设备上启动应用程序 . (我在首次启动前看到黑屏超过10秒)

    • 在Eclipse或Idea中打开项目作为标准gradle项目

相关问题