Странная структура проекта Gluon для JavaFX — портирование Android

Градиентная сборка подключаемого модуля Gluon (в Netbeans 8.0.2) для переноса JavaFX на Android создает следующие структуры каталогов:

  1. Исходные пакеты [Java]
  2. Пакеты Android/Java
  3. Пакеты рабочего стола/Java
  4. Пакеты iOS/Java

Каждый из этих каталогов содержит внутри себя пакеты Java. Обычно сборка Gluon создает для нас «основной» класс в одном java-пакете внутри каталога «Исходные пакеты» [название «Пакеты с исходными пакетами» может вводить в заблуждение, поскольку это не пакет Java, а просто каталог файловой системы]. Этот основной класс расширяет класс приложения Javafx и, таким образом, является точкой входа в наше приложение.

Android API доступен только в каталоге Android/Java Packages для любого java-пакета, созданного внутри него. Скажем, класс android.Vibrator доступен только здесь.

Проблема в том, что мы не можем ссылаться на класс, созданный внутри любого пакета Java в каталоге Android/Java, на любой пакет java, созданный в каталоге Source Packages [Java]!! Если это так, то как бы мы перевели приложение из метода start() javafx.Application, скажем, в android.Vibrator.

Структура проекта gluon имеет снимок по адресу: Как ссылаться android.jar в проекте Gluon


person nawazish-stackoverflow    schedule 29.08.2015    source источник


Ответы (1)


Как вы знаете, проект JavaFXPorts позволяет развертывать приложения JavaFX на устройствах Desktop, Android и iOS. Когда это просто чистый код JavaFX, проект добавляется в область действия Main, и оттуда он будет виден на всех этих платформах.

Только в том случае, если вам нужен код для конкретной платформы, вы должны добавить его в соответствующий пакет.

Как вы упомянули, по умолчанию из пакета Main вы не увидите добавленный код в пакете платформы, поэтому вы должны предоставить способ для этого.

Если вы посмотрите пример HelloPlatform в репозитории JavaFXPorts, вы найдете класс PlatformService для загрузки пакетов с помощью ServiceLoader.

Другая возможность — использовать Class.forName() для динамической загрузки классов во время выполнения, как только мы узнаем платформу, на которой работает приложение.

Я предлагаю вам взглянуть на проект Gluon Down, который управляет несколькими службами для конкретных платформ. , и предоставляет вам единый, независимый от платформы API.

Для тех сервисов, которые еще не доступны в Down (не стесняйтесь вносить свой вклад), вы можете реализовать их как в этом простом приложении, созданном с помощью плагина Gluon.

Исходные пакеты [Java]

Сначала создайте метод getPlatform() и добавьте указанные классы для каждой конкретной платформы. Например, добавьте org.gluonoss.vibrator.GluonAndroidPlatform.java в пакет Android.

public class GluonPlatformFactory {

    public static GluonPlatform getPlatform() {
        try {
            String platform = System.getProperty("javafx.platform", "desktop");
            String path = "org.gluonoss.vibrator.GluonDesktopPlatform";
            if(platform.equals("android")) {
                path = "org.gluonoss.vibrator.GluonAndroidPlatform";
            } else if(platform.equals("ios")) {
                path = "org.gluonoss.vibrator.GluonIosPlatform";
            }
            return (GluonPlatform) Class.forName(path).newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            System.out.println("Platform Error "+e.getMessage());
        }
        return null;
    }
}

Теперь создайте интерфейс с помощью метода, который вы хотите использовать на всех своих платформах:

public interface GluonPlatform {

    void vibrate();

}

Наконец, в вашем основном классе извлеките платформу и вызовите свой метод:

    @Override
    public void start(Stage stage) {
        final Button button = new Button("Click me!");

        button.setOnAction(e-> GluonPlatformFactory.getPlatform().vibrate());

        StackPane root = new StackPane(button);

        Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
        Scene scene = new Scene(root, visualBounds.getWidth(), visualBounds.getHeight());

        stage.setScene(scene);
        stage.show();
    }

Пакеты для рабочего стола/Java

Добавьте метод вибрации. Пока оставьте его пустым, но вы можете добавить Timeline, например, для перемещения кнопки.

 public class GluonDesktopPlatform implements GluonPlatform {

    @Override
    public void vibrate() {
        System.out.println("Vibrating!");
    }

}

Пакеты Android/Java

Добавьте метод вибрации. Обратите внимание, что мы должны использовать FXActivity, который является мостом между потоком JavaFX и активностью Android.

public class GluonAndroidPlatform implements GluonPlatform {

    @Override
    public void vibrate() {
        Vibrator v = (Vibrator) FXActivity.getInstance().getSystemService(Context.VIBRATOR_SERVICE);
        v.vibrate(500);
    }

}

Не забудьте добавить необходимое разрешение в файл AndroidManifest (вы найдете его в разделе src/android/AndroidManifest.xml.

Теперь вы можете развернуть проект и запустить его на рабочем столе (gradlew run), и он будет работать, и установить его на Android (gradlew androidInstall), и он тоже будет работать.

person José Pereda    schedule 30.08.2015
comment
Большое спасибо @ Хосе Переда. Поскольку для java.util.ServiceLoader важно явно указывать реализации поставщика услуг через распознающий файл в каталоге META-INF/services, и эта структура каталогов должна присутствовать в пути к классу во время выполнения приложения, то какие изменения необходимо внести в скрипте сборки gradle, чтобы установить путь к классам во время выполнения, указывающий на META-INF/services. Я очень новичок в gradle, поэтому любой вклад будет замечательным. - person nawazish-stackoverflow; 03.09.2015
comment
Я не думаю, что вам нужна какая-либо модификация. Пример HelloPlatform работает с ServiceLoader без каких-либо изменений в build.gradle. В любом случае, я предпочитаю подход Class.forName(), когда имена классов вставляются в код, поэтому вам не нужны дополнительные текстовые файлы. Вы пробовали образец вибратора? - person José Pereda; 03.09.2015
comment
@JosePeda. Большое спасибо за вашу помощь и объяснение. Я попробовал приведенный выше код, и он сработал как шарм; я использовал Class.forName(String) вместо ServiceLoader‹T›. Поскольку вы уже работаете над Charm Down и, как вы говорите, есть сервисы, которые еще предстоит создать, я хотел бы внести свой вклад в то же самое сейчас, поскольку теперь я чувствую некоторый уровень уверенности в JavaFXPorts. Профессионально я работаю над JavaFX для пользовательского интерфейса в сочетании с EJB в качестве серверных компонентов с такими стандартами, как RMI и JMS для интеграции. Я хотел бы обсудить с вами, я хотел бы знать, с какой службы я должен начать. - person nawazish-stackoverflow; 05.09.2015
comment
Хорошо знать! Мы можем перенести обсуждение на форум Gluon Charm. Также я предлагаю вам взглянуть на Gluon Charm, так как он включает, помимо Down, Connect for cloud сервисы и Glisten для пользовательского интерфейса. - person José Pereda; 05.09.2015
comment
Переда, я создал тему по адресу: gluonhq.com/forums/topic/ Не могли бы вы внести свой вклад. - person nawazish-stackoverflow; 18.09.2015