2015-07-26

Here's to jjsb4a

Vielleicht erinnern Sie sich an meinen Post über den glücklosen Versuch, JSR 223 unter Android lauffähig zu machen. Damals habe ich beschrieben, dass es nicht klappt, weil in javax.script.ScriptEngineManager auf die nicht vorhandene Klasse sun.misc.Service zugegriffen wird. Und ich hatte angedeutet, mir Gedanken über eine entsprechende Wrapper-Klasse zu machen. Denn seit Java 6 gibt es mit ServiceLoader ja eine Alternative, die auch unter Android vorhanden ist.

Der Wrapper ist in trivialer Form fertig. Damit steht JSR 223 unter Android zur Verfügung. Oder auch nicht, denn die Rhino-Version, die mit der Referenzimplementierung ausgeliefert wird, erzeugt zur Laufzeit Bytecode. Und das klappt unter Android aus naheliegenden Gründen nicht. Wer mehr darüber erfahren möchte, kann dies in zwei Talks tun, die ich auf dem Herbstcampus und der TopConf Linz halten werde.

Allerdings ist in Android ja ein moderner JavaScript-Interpreter enthalten. Auf ihn zugegriffen werden kann über die Klasse WebView, also die Browser-Komponente. Warum sollte sich dies nicht nutzen lassen, um doch noch JSR 223 lauffähig zu bekommen?

Hier kommt mein Mini-open source-Projekt jjsb4a ins Spiel, das seit heute auf GitHub zu finden ist. Der unaussprechliche Name bedeutet übrigens Java-JavaScript-Bridge for Android. Derzeit kommt die Brücke noch nicht als eigenständiges Jar daher, sondern in Gestalt einer Demo. Sie befindet sich nämlich noch im Rohbau. Erste kleine Versuche sind aber möglich.

Übrigens wäre Android vermutlich nicht Android, wenn es nicht auch hier ein kleines caveat geben würde. Mehr dazu finden Sie im readme.

2015-07-12

Es will einfach nicht klappen, Ausgabe 20150712

Seit vielen Versionen ist es out of the box möglich, aus Java heraus Scriptsprachen aufzurufen. Der JSR 223 (Scripting for the Java Platform) hat nämlich schon mit Java SE 6 Einzug in die Plattform gehalten.

ScriptEngineManager m = new ScriptEngineManager();

ScriptEngine engine = m.getEngineByMimeType("application/javascript");

String program = "print('Hello, World!')";

try {

    engine.eval(program);

catch (ScriptException ex) {

    LOGGER.log(Level.SEVERE, null, ex);

}


Regelmäßige Leser meines Blogs wissen, dass ich meine Java-Gewohnheiten gerne auch unter Android ausleben möchte. Warum also nicht zum Beispiel auf die oben gezeigte Weise JavaScript integrieren? Erste Antwort: weil das Paket javax.script einschließlich seiner Unterpakete nicht in der Android-Klassenbibliothek enthalten ist. Gut, aber zu jedem Java Specification Request gibt es eine Referenzimplementierung. JSR 223 macht da keine Ausnahme. Warum also nicht diese nutzen? Die wenigen Jars sind schnell hinzugefügt, der Code wird übersetzt, die App startet. ...rrruuuuuuummmmsssss...... Vielleicht erinnern Sie sich ja an meine glücklosen Versuche, JAX-WS zu nutzen. Der Pessimist in mir ist nun geneigt zu fragen, warum es gerade jetzt hätte funktionieren sollen. Aber natürlich ist einfach so aufgeben uncool, und deshalb habe ich kurz den Debugger bemüht. Das ernüchternde Ergebnis: die Implementierung möchte gerne die Klasse sun.misc.Service nutzen. Und die ist (natürlich) nicht vorhanden. Was bedeutet das?

JSR 223 setzt auf einen einfachen Serviceprovider-Mechanismus, der an unterschiedlichen Stellen in der Java-Standardklassenbibliothek Verwendung findet. Dazu wird in einem .jar-Archiv eine Textdatei META-INF/services abgelegt, die der Java-Konvention für Klassennamen folgt, zum Beispiel javax.script.ScriptEngineFactory. Sie enthält eine Liste von Klassen, die das Interface mit dem Namen der Datei implementieren. Auf diese Weise findet eine Entkopplung zwischen Vertrag und Implementierung statt. Bleibt die Frage, wie die Auflösung bzw. das Finden der implementierenden Klassen funktioniert. Tja, und hier kommt sun.misc.Service ins Spiel. Übrigens gibt es seit Java 6 die Klasse ServiceLoader. Sie scheint aus Service hervorgegangen zu sein. Die kennt Android seit API Level 9 sogar.

Dumm nur, dass die Referenzimplementierung von JSR 223 sie nicht nutzt. Mal sehen, ob ich mir in einer ruhigen Minute mal ansehe, wie aufwendig der Umzug wäre...

2015-07-08

Android Emulator funktioniert nicht mehr – und was man dagegen tun kann

Kennen Sie das? Man ärgert sich über ein Problem, geht ihm aber nicht entschlossen genug nach. Bei mir war dies bei dem folgenden Dialog so…:

Screenshot: Android Emulator-Absturz

Er erschien sehr oft, wenn ich das Android Emulator-Fenster schließen wollte. Aber eben nicht immer. Heute habe ich mir vergegenwärtigt, was ich (üblicherweise) in welcher Reihenfolge tue:

  1. Android Studio beenden
  2. Emulator beenden

Halt. Warum nicht einfach diese Reihenfolge umkehren? Um es kurz zu machen – die Abstürze sind weg. Ich verkneife mir an dieser Stelle eine tiefgreifende Analyse und freue mich über den nicht mehr erscheinenden Dialog.

2015-07-03

Schöne neue Welt, Teil 3

In meinem vorherigen Post hatte ich eine Lösung für das nicht so ganz einfache Speichern von Fenstergröße und -position in JavaFX angedeutet. Wer sich meine Implementierung ansehen möchte, sollte einen Blick auf folgendes Bitbucket Snippet werfen.
Das Dilemma war ja, dass die vier Propertyänderungen zu unterschiedlichen Zeiten auflaufen. Ich sorge nun einfach dafür, dass Aktualisierung innerhalb einer Sekunde genau einmal betrachtet werden - und zwar nochmal eine Sekunde später. Nehmen Sie an, das Fenster wurde verschoben oder vergrößert. In diesem Fall ändert sich entweder das Paar x/y, oder Breite/Höhe. Die erste Änderung sorgt dafür, dass ein Thread gestartet wird. Dieser wartet eine Sekunde, und schreibt dann Position und Größe in die Benutzereinstellungen. Die zweite Änderung darf nicht noch einen neuen Thread starten. Das verhindere ich auf triviale Weise, indem ich einfach prüfe, vor wie vielen Millisekunden die letzte Änderung stattgefunden hat. Alles was kürzer als 1 Sekunde zurück liegt, wird verworfen. Da es sehr wahrscheinlich ist, dass alle vier Änderungen innerhalb von 1000 Millisekunden feuern, wird nur einmal der Zustand gesichert.
Auf diese Weise bekomme ich auch den inkonsistenten Zustand beim Maximieren in den Griff. Probeiren Sie es am besten einfach aus.