MySQL in Gluon Mobile

Warum Gluon?

Für mein Privates Heimautomatisierungsprojekt hatte ich bereits PIPO x8 Boxen (Amazon sponsored Link) als stationäre Bildschirme besorgt, die sowohl mit Windows 10 als auch mit Android 4.4 ihren Dienst verrichten können. Da in Zukunft auch das ein oder andere Smartphone mit angebunden werden sollte, war es mir heute ein Anliegen, ein kleines Template zu erstellen, welches zumindest schon einmal die Anbindung an eine SQL Datenbank beinhaltet und sowohl nativ auf dem MAC, Android und Windows Geräten lauffähig ist. All das bietet Gluon Mobile mit dem Zusatz, dass auch iOS abgedeckt werden kann, wenn man eine RoboVM Lizenz sein Eigen nennt. Warum nicht gleich eine native Android oder "normale" JavaFX Application? Weil ich noch nicht genau weis, ob ich die Pipo Boxen mit Windows 10 oder betreiben werde oder doch lieber mit Android. Letztere Variante hätte den Charm, dass es bereits viele andere kleine Apps gibt, die auf den Boxen genutzt werden könnten (Spotify, Foscam CamViewer, Netflix, etc..) und mir der Windows Store derzeit noch ein wenig zu leer erscheint. Außerdem hatten die ersten Versuche mit Windows 10 leider ein paar negative Seiten von Windows ans Tageslicht befördert: Ständige Updates, Neustarts und unzählige UIs um Stromspar Funktionen zu konfigurieren.

Gluon gibt mir an dieser Stelle die Möglichkeit, den Client zu implementieren und mich bzgl. der Plattform später entscheiden zu können.

MySQL sollte nicht unbedingt das Problem sein, oder?

Nun, eigentlich nein. Dachte ich jedenfalls. Wenn es um JavaFX als solches geht, hatte ich in den letzten Monaten nie ein Problem. Allerdings zeigt eine kurze Suche nach "MySQL" und "Android" recht schnell, dass JDBC im Android Umfeld nicht die erste Wahl ist - ja, wenn überhaupt dann nur zusammen mit einem PHP Interface verwendet wird. Die angeführten Gründe dazu leuchten teilweise ein - wollen wir das mal nicht vertiefen. In meinem Fall möchte ich aber trotz allem MySQL verwenden. Der Client verrichtet seinen Dienst ja ohnehin nur im lokalen Netzwerk zu Hause. Der Weg zum Ziel in Kurzfassung um JDBC MySQL und Android zur Kooperation zu bewegen:

  • Gluon Projekt von Standard Template erzeugen (Gradle)
  • androidSdk Pfad / Variable im Build Script setzen (Gradle)
  • Ignorieren von META-INF ins Build Script setzen (Gradle)
  • MySQL connector besorgen und ins /lib Verzeichnis kopieren oder
  • besser noch im Gradle script den connector als dependency hinzufügen
  • Code aus dem snippet unten anpassen und benutzen um SQL statements zu senden...
  • fertig?...

Und los...

Anpassungen am .gradle script

Die ersten fünf (bzw. vier) Bullet Points beinhalten Aufgaben die wir am .gradle build script abarbeiten müssen. Hier also das Resultat. Für euer eigenes Projekt müssen natürlich die Pfade usw. angepasst werden. Ich gehe jetzt einfach mal nicht davon aus, dass Ihr euer Android SDK an der selben Stelle hinterlegt habt wie ich. Also bitte nicht nur copy paste anwenden sondern den Inhalt für eure eigene Umgebung anpassen.

Übrigens: In meinen Versuchen gelang mir die Kommunikation mit dem DB Server nur mit einer etwas älteren Version des Connectors ('mysql:mysql-connector-java:3.1.12')!

<pre class="lang:default decode:true" title="build.gradle">buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'org.javafxports:jfxmobile-plugin:1.0.7'
    }
}

apply plugin: 'org.javafxports.jfxmobile'

repositories {
    jcenter()
    maven {
        url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
    }
}

dependencies{
    compile 'mysql:mysql-connector-java:3.1.12'
}

mainClassName = 'com.gluonandroidmysqlexample.GluonAndroidMySQLExample'

dependencies {
    compile 'com.gluonhq:charm:2.1.0'

    androidRuntime 'com.gluonhq:charm-android:2.1.0'
    iosRuntime 'com.gluonhq:charm-ios:2.1.0'
    desktopRuntime 'com.gluonhq:charm-desktop:2.1.0'
}

jfxmobile {
    android {
        manifest = 'src/android/AndroidManifest.xml'
        packagingOptions{
            exclude 'META-INF/INDEX.LIST'
        }
        androidSdk = '/Library/android-sdk-macosx'
    }
}</pre>

Verbindung zum MySQL Server aufbauen und ein Statement ausführen

Nach den Anpassungen im build script kann jetzt munter losgelegt werden. Hier eine kleine Beispiel Implementation:

<pre class="lang:java decode:true ">package com.gluonandroidmysqlexample;

import com.gluonhq.charm.glisten.control.AppBar;
import com.gluonhq.charm.glisten.control.Icon;
import com.gluonhq.charm.glisten.mvc.View;
import com.gluonhq.charm.glisten.visual.MaterialDesignIcon;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.lang.*;

public class BasicView extends View {

    public BasicView(String name) {
        super(name);

        Label label = new Label("Hello JavaFX World!");

        Button button = new Button("Change the World!");
        button.setGraphic(new Icon(MaterialDesignIcon.LANGUAGE));
        button.setOnAction(e -&gt; label.setText(request()));

        VBox controls = new VBox(15.0, label, button);
        controls.setAlignment(Pos.CENTER);

        setCenter(controls);

    }

    @Override
    protected void updateAppBar(AppBar appBar) {
        appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -&gt; System.out.println("Menu")));
        appBar.setTitleText("Basic View");
        appBar.getActionItems().add(MaterialDesignIcon.SEARCH.button(e -&gt; System.out.println("Search")));
    }

    private static String request(){
        String url = "jdbc:mysql:///*put your database url here*/:3306//*and database name here*/";
        String user = "myUserName";
        String passwd = "fencyPassword";

        String result = "none";

        try{ // Loading the MySQL Connector/J driver
            Class.forName("com.mysql.jdbc.Driver");
        }catch(ClassNotFoundException e){
            result = "Error while loading the Driver: " + e.getMessage();
            System.out.println("Error while loading the Driver: " + e.getMessage());
            return result;
        }

        Connection conn = null;
        try{
            /* Initializing the connection */
            conn = DriverManager.getConnection(url, user, passwd);

            Statement statement = conn.createStatement();

            ResultSet resultset = statement.executeQuery("select * from tablename limit 10, 10;");
            result = "";
            while(resultset.next()){
                      result = String.format("%s ... %d", result, resultset.getInt("columNameInTable"));
            }

        }catch(SQLException e){
            result = "SQL connection error: " + e.getMessage();
            System.out.println("SQL connection error: " + e.getMessage());
        }finally {
            if(conn != null){
                try{
                    /* CLosing connection */
                    conn.close();
                }catch (SQLException e){
                    result = "Error while closing the connection: " + e.getMessage();
                    System.out.println("Error while closing the connection: " + e.getMessage());
                }
            }
        }
        return result;
    }

}

Previous Post Next Post