Groovy on Android-Not Quite There Yet

Posted     

Edit(3 AUG 09): Since this post was written there has been some success with getting some low level Groovy running on Android. Check out the project here: http://code.google.com/p/discobot/downloads/list

Disclaimer: This is the product of some 5-6 hours or so of messing around.There might be a better way to do things. The main goal of this entry is to get people thinking about it.

First the good news.

The UI for Android doesn’t use Hildon or some other abstract ui framework. If you can layout a web page with absolute positioning with ease, you’ll have no problems here. Android uses very readable XML files for the layouts.

Now for the bad news:
Because it doesn’t use a full J2SE JRE/JDK, Groovy doesn’t work out of the box. Here’s what I’ve got so far.

1. After installing the Android SDK, create a new application with the command: ./activityCreator.py --out myproject your.package.name.ActivityName
or you could use the Eclipse plugin.

2. Add a Groovy compile task to the generated Ant build file and include the appropriate library jars on its classpath.

3. You can compile right now with ant and install the application to the emulator(after starting the emulator) with adb install [in bin directory of your project]. In a separate window you can see the output of the running emulator with by starting a debug shell, adb shell and then running logcat. At this point it’s complaining about ’groovy/lang/GroovyObject’[ClassNotFoundException].

4. All classes need to be converted to Davlik’s dex format. The dx command does this. I tried to convert the groovy-all jar and the contents of the groovy/lib directory in separate attempts but I was getting heap overflow errors. To remedy this, I expanded the jar into bin/classes and removed the swing specific bits. It’s not required to remove them but it lessens the likelyhood of a heap over flow. Now rerun the ant task to include them in the application package.

5. We get complaints about java.beans.Inspector which is located in rt.jar(in one of the jre directories). I extracted all the files in the java.beans directory into bin/classes. The next missing dependency is one of the classes in sun.reflect.misc. I extracted all the files from that directory into bin/classes as well.

The final status: A ClassNotFoundException and ClassCastException from inside the android jar. Here’s the output from the log
D/dalvikvm( 636): Exception java/lang/ClassNotFoundException from ApplicationLoaders.java:188 not caught locally
D/dalvikvm( 636): NOTE: loadClass ’groovy/runtime/metaclass/CustomMetaClassCreationHandle’ 0x4001d608 threw an exception
D/dalvikvm( 636): Exception java/lang/ClassNotFoundException from ApplicationLoaders.java:188 not caught locally
D/dalvikvm( 636): NOTE: loadClass ’groovy/runtime/metaclass/org/codehaus/groovy/runtime/ScriptBytecodeAdapterMetaClass’ 0x4001d608 threw an exception
D/dalvikvm( 636): Exception java/lang/ClassCastException from MetaClassRegistryImpl.java:168 not caught locally
D/dalvikvm( 636): Exception java/lang/RuntimeException from Looper.java:76 not caught locally
D/dalvikvm( 636): Exception java/lang/RuntimeException from ZygoteInit.java:1176 not caught locally
D/AndroidRuntime( 636): Shutting down VM
W/dalvikvm( 636): threadid=3: thread exiting with uncaught exception (group=0x4000e648)
E/AndroidRuntime( 636): Uncaught handler: thread Main exiting due to uncaught exception
E/AndroidRuntime( 636): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{groovy.tests/groovy.tests.HelloWorld}: java.lang.ClassCastException
E/AndroidRuntime( 636): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1338)
E/AndroidRuntime( 636): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1410)
E/AndroidRuntime( 636): at android.app.ActivityThread.access$1200(ActivityThread.java:76)
E/AndroidRuntime( 636): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:980)
E/AndroidRuntime( 636): at android.os.Handler.dispatchMessage(Handler.java:80)
E/AndroidRuntime( 636): at android.os.Looper.loop(Looper.java:71)
E/AndroidRuntime( 636): at android.app.ActivityThread.main(ActivityThread.java:2506)
E/AndroidRuntime( 636): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 636): at java.lang.reflect.Method.invoke(Method.java:380)
E/AndroidRuntime( 636): at android.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1170)
E/AndroidRuntime( 636): at android.os.ZygoteInit.main(ZygoteInit.java:1121)
E/AndroidRuntime( 636): at android.dalvik.NativeStart.main(Native Method)
E/AndroidRuntime( 636): Caused by: java.lang.ClassCastException
E/AndroidRuntime( 636): at java.util.Arrays.binarySearch(Arrays.java:365)
E/AndroidRuntime( 636): at org.codehaus.groovy.reflection.CachedMethod.find(CachedMethod.java:59)
E/AndroidRuntime( 636): at groovy.lang.MetaClassImpl.applyPropertyDescriptors(MetaClassImpl.java:1659)
E/AndroidRuntime( 636): at groovy.lang.MetaClassImpl.setupProperties(MetaClassImpl.java:1429)
E/AndroidRuntime( 636): at groovy.lang.MetaClassImpl.addProperties(MetaClassImpl.java:2319)
E/AndroidRuntime( 636): at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:2299)
E/AndroidRuntime( 636): at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:160)
E/AndroidRuntime( 636): at org.codehaus.groovy.runtime.Invoker.invokeStaticMethod(Invoker.java:120)
E/AndroidRuntime( 636): at org.codehaus.groovy.runtime.InvokerHelper.invokeStaticMethod(InvokerHelper.java:84)
E/AndroidRuntime( 636): at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeStaticMethodN(ScriptBytecodeAdapter.java:230)
E/AndroidRuntime( 636): at groovy.tests.HelloWorld.(HelloWorld.groovy)
E/AndroidRuntime( 636): at java.lang.Class.newInstance(Native Method)
E/AndroidRuntime( 636): at android.app.Instrumentation.newActivity(Instrumentation.java:760)
E/AndroidRuntime( 636): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1334)
E/AndroidRuntime( 636): ... 11 more

Not quite there yet but it’s close...failing just before the ApplicationLoader. I wish I could root around more in the android jar. So that’s it kids, I hope you don’t hold it against me if you thought I had a solution. There is a decent penalty for all the extra classes. The final versions spins for about 3 secs before failing.


Comments

  1. Android App said:

    I played with this for a while too. It's good to know I wasn't the only one.
  2. ClassFoo said:

    i tried to compile the Jython and get the some messages, seems like some bugs in java.lang.reflect in dalvik...
  3. Kevin Galligan said:

    I did some reflection in my submission, and ran into some issues there. Literally, code that worked in standard SE was returning strange stuff in Android. Had to massage the code. I'm sure it wouldn't work in a standard JVM now. Any update on this? I'd love to have it.
  4. JW said:

    Unfortunately not, reflection is a core part of Groovy and that's what kills the idea. IMHO a Groovy that would run on Android(w/o reflection) really wouldn't be Groovy at all.
  5. louboutinshoespub said:

  6. rosetta stone said:

    You write good articles, I will always be concerned about
  7. ?? said:

    goods
blog comments powered by Disqus