Steve On Java - JavaFX

Hacking Java, JavaFX, and Flash with Agility
  • rss
  • Home
  • NightHacking Tour
    • [Archive] NightHacking Europe – The Road to Devoxx
  • SvJugFX
  • JFXtras
    • JFXtras Individual CLA
    • JFXtras Corporate CLA
  • 2013 Travel Map
    • Let’s Meetup!
    • 2012 Travel Map
  • Contact

Visage Android – Cleaner APIs, Cleaner UIs

steveonjava | January 13, 2011

I have been busily working away at getting Visage ready for developing Android applications. It is a great fit, because Android converts regular Java class files into its special class format, and the Visage compiler happens to generate Java class files. Also, Android is desperately in need of some TLC on their APIs (more on this in a future blog).

So why use Visage for coding Android applications? We do a yearly Hack-a-Thon event at my company (this year called the GXS Xathon). The winning application was written by Tim McNamara, one of my coworkers, and happened to be an Android application.  I decided to do a small port of his code to see if I could improve the maintainability using Visage.  Here is a screenshot of the application:

A base settings page for an application.  It uses a couple edit text fields, several lists, and takes advantage of the summary line to display the current values.  The original version included:

  • A Java PreferenceActivity class file
  • An XML UI layout descriptor
  • Another XML file for array resources

Believe it or not, this is the minimum necessary set of files to create the above screen.  In converting this to Visage, my goal was to get rid of a lot of the redundancy and glue code needed to work across 3 different files.

The end results of the conversion were as follows:

FilesLinesCharacters
Raw Android1 Java, 2 XML2087413
Visage Android1 Visage903640

While the numbers are impressive, what really matters is the code.

Here is the final Visage code for the settings page:

public class Settings extends PreferenceActivity {
    var senderPref:ListPreference;
    var receiverPref:ListPreference;
    var statusPref:ListPreference;
    var pollingPref:ListPreference;
    var passwordPref:EditTextPreference;
    var usernamePref:EditTextPreference;

    override var screen = PreferenceScreen { // 1
        preferences: [
            PreferenceCategory { // 1
                "Preferences" // 2
                preferences: [
                    usernamePref = EditTextPreference { // 1...
                        "Username" // 2
                        key: "usernamePref"
                        summary: bind if (usernamePref.text == "") "Currently undefined" else "Current value: {usernamePref.text}" // 3
                    }
                    passwordPref = EditTextPreference {
                        "Password"
                        key: "passwordPref"
                        summary: bind passwordPref.text.replaceAll(".", "*"); // 3
                    }
                    pollingPref = ListPreference {
                        "Polling Interval"
                        key: "pollingPref"
                        defaultValue: "60000"
                        entries: ["30 seconds", "1 minute", "5 minutes", "10 minutes", "15 minutes", "30 minutes", "1 hour"] // 4
                        entryValues: ["30000", "60000", "300000", "600000", "900000", "1800000", "3600000"] // 4
                        summary: bind pollingPref.entry
                    }
                ]
            }
            PreferenceCategory {
                "Filter"
                def CLEAR = "\{Clear Filter\}"; // 5
                preferences: [
                    statusPref = ListPreference {
                        def status = [CLEAR, "HEALTHY", "WARNING", "DOWN"]; // 5
                        "Filter By Status"
                        key: "statusPref"
                        defaultValue: CLEAR
                        entries: status
                        entryValues: status
                        summary: bind if (statusPref.value == CLEAR) "Select a status to filter on." else "Current value: {statusPref.value}"
                    }
                    senderPref = ListPreference {
                        def senders = [CLEAR, for (s in ConnectionService.getSenderNameList()) s];
                        "Filter By Sender"
                        key: "senderPref"
                        defaultValue: CLEAR
                        entries: senders
                        entryValues: senders
                        summary: bind if (senderPref.value == CLEAR) "Select a sender to filter on." else "Current value: {senderPref.value}"
                    }
                    receiverPref = ListPreference {
                        def receivers = [CLEAR, for (r in ConnectionService.getReceiverNameList()) r];
                        "Filter By Receiver"
                        key: "receiverPref"
                        defaultValue: CLEAR
                        entries: receivers
                        entryValues: receivers
                        summary: bind if (receiverPref.value == CLEAR) "Select a receiver to filter on." else "Current value: {receiverPref.value}"
                    }
                ]
            }
        ]
    }
}

While I am not going to include the full original Android code (200 lines is a lot of code!), here are some of the changes that made the Visage version much more succinct (the below bullets match the numbers in the comments above):

  1. The Visage object literal syntax is more concise than XML and just as readable!
  2. Default properties make the object literal syntax even more concise
  3. One bind call can replace dozens of lines of code to setup and instantiate event listeners
  4. No need to declare arrays in a separate file (yes, we have real data types)
  5. This is a real programming language, so you can use constants and variables to repeat arguments (try doing that in XML!)

All of the technology here is real, but getting a completed set of APIs that covers all of the things you can accomplish in Android is still a work in progress.

If you are interested in helping out with this, please join the Visage Developers mailing list.  I will be posting instructions there soon on how to access the bleeding edge Android Visage repository, and contribute to the growing set of Android APIs.

 

Share this:

  • Twitter
  • Google +1
  • More
  • Facebook
  • LinkedIn
  • Email
Categories
Android, JavaFX, Visage
Tags
Android, api, ui, Visage
Comments rss
Comments rss
Trackback
Trackback

« Alternative Languages at Devoxx and Soon JavaOne Brazil JavaFX 2.0 at the Chennai JUG »

21 Responses to “Visage Android – Cleaner APIs, Cleaner UIs”

  1. Luis Barragan says:
    January 13, 2011 at 5:14 am

    Interesting and the numbers indeed are impressive.

    On the other hand there are things I like about having separate files, e.g. keeping the locale dependent text in a file to make it easier to internationalize the app… specially here in Europe.

    Reply
    • steveonjava says:
      January 13, 2011 at 8:01 pm

      The original example with its 3 files was not localized either… you would have had to use a fourth Strings.xml file if you wanted to add localization.

      For Visage the plan is to support localization using a similar mechanism to JavaFX. This includes a syntax like the following:
      ##”Filter By Status”

      You would then add a properties file in to the same directory with the name “Settings_en.fxproperties” and the following contents:
      “Filter By Status” = “Your localized string here”

      This should meet the need and be much more developer friendly than Android localization technique. (e.g. No more Force Close messages when a localization file is missing a required string)

      Reply
  2. rob says:
    January 13, 2011 at 5:16 am

    Looks nice and useful, great work! But what happens when multiple screen sizes and languages must be supported? Android isolates those things in the two extra XML files, how will Visage do it?

    Reply
  3. João Bosco Monteiro says:
    January 13, 2011 at 5:33 am

    Absolutely amazing! Great job!

    Reply
  4. Mark Anro Silva says:
    January 13, 2011 at 6:32 am

    Very impressive. Thanks Steve.

    Reply
  5. JOKe says:
    January 13, 2011 at 7:47 am

    Great I am happy seeing JavaFX ( Visage ) on Android

    Reply
  6. William Siqueira says:
    January 13, 2011 at 1:10 pm

    Steve, congratulations for you and your partners! Great work!

    Reply
  7. pron says:
    January 13, 2011 at 1:13 pm

    Beautiful. Does this use any kind of runtime library (for the binding) or is everything done by the compiler?

    Reply
    • steveonjava says:
      January 13, 2011 at 8:03 pm

      It is a combination of a compiler and a runtime library. I didn’t include the imports, but all of the classes referenced in the Visage example are delegate objects with hand-crafted APIs that are close to their original Android counterparts, but with some improvements to take advantage of Visage language features.

      Reply
  8. Nick Apperley says:
    January 13, 2011 at 2:09 pm

    Fantastic work! Quite a feat to get data binding working on Android. Are wrapper (library) APIs being used in the example?

    Can one use the Android (platform) APIs? If so is it possible to use a mixture of the library and platform APIs?

    Is a runtime required for distribution with the example app? Creating Android apps using Visage would only be practical if it can be done without requiring a runtime to be distributed, and the library is kept extremely small in size. Also if one does not use the library then it should not be required for distribution with the app.

    As a suggestion the example can be improved by replacing pollingPref with the following (provided the map data type exists):

    ——————————————————————————————
    // Omitted code for brevity
    // Map declaration
    def listItems = ["30 seconds" -> "30000", "1 minute" -> "60000", "5 minutes" -> "300000", "10 minutes" -> "600000", "15 minutes" -> "900000", "30 minutes" -> "1800000", "1 hour" -> "3600000"];

    pollingPref = ListPreference {
    “Polling Interval”
    key: “pollingPref”
    defaultValue: “60000″
    entries: listItems.keys() entryValues: listItems.values()
    summary: bind pollingPref.entry
    }
    ——————————————————————————————

    Presumably the map data type doesn’t exist so treat this as a hypothetical change for now…………

    Reply
    • steveonjava says:
      January 13, 2011 at 8:08 pm

      The example here uses a runtime library in addition to the compiler. You can actually code the same thing without the runtime library in Visage, but it ends up looking (not surprisingly) a lot like the Java version. It is also possible to use the Visage delegate classes and native Android calls together (each delegate object has a public reference to the wrapped class).

      The plan for distributing the runtime library is to make it an application on the Android store that you can have a dependency against. This will mean that the end user only has to install the Visage APIs once and every application that uses them will be able to take advantage of the same code.

      The other distribution option is to include the subset of the runtime library files that you use by using a shrinker utility like ProGuard. This would allow you to keep your application size very small, only including the Visage classes that are actually in use.

      I actually had the same idea about using a Map datatype for the entries/entryValues. That is on the roadmap for Visage, so when we get it implemented we will definitely make use of it in the APIs.

      Reply
  9. Nick Apperley says:
    January 13, 2011 at 5:17 pm

    Rob – A single layout when properly done can handle most situations involving multiple screen sizes. Different screen sizes are handled better by a declarative language since it can minimize redundancy via looping/functions for instance, and the code is more readable than XML which makes it easier to maintain layouts. Also many declarative languages allow you to place layout type code in separate source files (loose coupling). In some ways the loose coupling is stronger than XML because you can break down the layout generation into variables, constants, classes, objects, modules, and functions.

    Android has a number of general and specialized layouts that automatically handle screen sizing by default (no further changes needed). If the target screen is bigger or smaller then the layout will automatically resize to fit.

    JavaFX Script has the built in ability to reference locale based strings (from fxproperties files), and change the locale at runtime which will change what strings are displayed automatically. If Visage has already got that facility then it is a matter of having the implementation reworked to use XML instead of fxproperties files for Android, JavaFX will stay the same.

    Reply
  10. Fernando Martines says:
    January 14, 2011 at 1:53 am

    Impressive work Steve! It is a great milestone for Visage. Thank you for keeping JavaFX alive, more than ever, by reaching the growing Android-based ecosystem.

    Reply
  11. eduveks says:
    January 14, 2011 at 6:32 am

    Great news! Congratz by effort!

    I hope use it in short time. I loved work with JavaFX and for Android even better!

    Great job and please keep going don’t stop!

    Reply
  12. pron says:
    January 14, 2011 at 11:05 am

    Visage really is a great UI language. I would love to see it used in making web applications, as it is far superior to HTML+Javascript+CSS. As a first attempt, instead of compiling visage (or its emitted bytecode) down to to Javascript a-la GWT, what about wrapping the common DOM API (org.w3c.dom) as Visage controls?
    This way a Visage applet could be used instead a an AJAX solution.

    Reply
    • Nick Apperley says:
      January 14, 2011 at 1:55 pm

      With the next iteration of JavaFX there may be a set of DOM APIs exposed (Java style), which Visage and other JVM languages can use. I am not entirely sure what the final plan for JavaFX 2 is on the web front. Although there is a web renderer as I understand it everything that is displayed is compiled to JavaScript unfortunately :(

      Reply
      • pron says:
        January 15, 2011 at 5:14 am

        The web-renderer is nice (perhaps for desktop apps, air-style), but it seems that when it comes to the web, the world is going the way of a plugin-free browser-page. Even flash is in peril. But a “headless” JVM applet that manipulates the DOM instead of Javascript may be appealing, especially if it could be written in a good language like Visage. A DOM API exists today (org.w3c.dom) and is available to applets, but it’s clunky to use from Java. It seems to me, that other than Android, this would be the best use of Visage as of now, and possibly even when JavaFX 2 arrives.

    • Nick Apperley says:
      January 14, 2011 at 5:05 pm

      Just confirmed with the roadmap for JavaFX 2 that there will be a set of DOM APIs (in the JavaFX 2 beta) :)

      – http://javafx.com/roadmap/#23

      Reply
  13. Gottfried Theimer says:
    January 19, 2011 at 11:37 am

    I have been wishing for an Android Visage very much but recently gave up hope almost entirely. Now this is very encouraging. Perhaps Visage on Android finally gets the developer interest that the JavaFX language deserved but never achieved. Very impressive.

    Reply
  14. Venkat says:
    December 27, 2012 at 11:40 am

    Is visage abandoned ?

    Reply
    • steveonjava says:
      December 27, 2012 at 12:00 pm

      I am working on some compiler changes to allow for automatic detection of JavaFX APIs. So not abandoned, but also not ready for end user use.

      Reply

Leave a Reply

Click here to cancel reply.

  • Travel Map - Let's Meetup

Publications

  

Affiliations

Awards

2009/2011 JavaOne Rock Star!

Disclaimer

Views and opinions expressed here are all my fault... complain to me, not my employer. :)
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox
loading Cancel
Post was not sent - check your email addresses!
Email check failed, please try again
Sorry, your blog cannot share posts by email.