Scala on Android 101 – Proguard, XmlParser and Function2AsyncTask 4

I’ve neglected my blog for a while so I though I’d share my latest experiments with running Scala on Android. In order to try a couple of things with Scala on Android I’m creating an Activity which  basically trying to consume a WebService and display the results in a List.Please keep in mind that I’m only learning Scala now so I’ll gladly get any comments and/or suggestions regarding my solutions.These are the problems I’ve found  :

  • PROBLEM #1
    • The scala-library.jar is too big to dex so you have to use ProGuard to keep things small. Try making it work properly with maven and you’ll have issues with getting all the plugins working in the right order!
  • SOLUTION #1
    • Ditch maven! “But having it manage my dependencies is so cool…” I hear you say.. well let’s use Ivy:

Just use one of the numerous ANT build scripts for Android and add the targets for Ivy and ProGuard and the scala repository to your ivysettings.xml:

.....
<url name="scala-tools.org">
     <artifact pattern="http://scala-tools.org/repo-releases/[organisation]/[module]/[revision]/[module]-[revision].[ext]" />
  </url>
....

add your dependencies to your ivy.xml:…

<dependency org="org/scala-lang" name="scala-library" rev="2.8.0.r18462-b20090811081019"/>
<dependency org="org/scala-lang" name="scala-compiler" rev="2.8.0.r18462-b20090811081019"/>
<dependency org="net/sf/proguard" name="proguard" rev="4.3"/>
....

Add some nice Ivy targets:

<taskdef resource="org/apache/ivy/ant/antlib.xml"
     uri="antlib:org.apache.ivy.ant" classpath="${ivy.jar.dir}/ivy.jar"/>

 <target name="init-ivy" depends="download-ivy">
 	<ivy:settings file="${basedir}/ivysettings.xml" />
        <ivy:retrieve />
</target>

  <target name="download-ivy">
    <mkdir dir="${ivy.jar.dir}"/>
    <get src="http://www.integratebutton.com/repo/
       ${ivy.install.version}/ivy-2.0.0-beta2.jar"
      dest="${ivy.jar.file}" usetimestamp="true"/>
  </target>

a nice ProGuard target:

    <target name="proguard" depends="compile">
      <taskdef resource="proguard/ant/task.properties"
               classpath="${external-libs}/proguard-4.3.jar" />
      <proguard>
-injars ${outdir}/classes:${external-libs}/scala-library-2.8.0.r18462-b20090811081019.jar(!META-INF/MANIFEST.MF,!library.properties)
-outjars ${outdir}/classes.min.jar
-libraryjars ${android-jar}
-dontwarn
-dontoptimize
-dontobfuscate
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-allowaccessmodification
-keep public class <your main class here>
-keep interface scala.ScalaObject
      </proguard>
    </target>

and you’re good to go!

  • PROBLEM #2
    • Scala uses the Java SAX parser which kept complaining about the use of namespace prefixes so I had to come up with a way to toggle this feature.
  • SOLUTION #2
    • Use my own SAX parser instance with the right features toggled :
object XmlParser {
  // Workaround for namespace prefix
  private val namespacePrefixes = "http://xml.org/sax/features/namespace-prefixes"
  val parser = javax.xml.parsers.SAXParserFactory.newInstance()
  parser.setNamespaceAware(false)
  parser.setFeature(namespacePrefixes, true)

  def load(i:InputStream) = XML.withSAXParser(parser.newSAXParser()).load(i)
}
  •  PROBLEM #3 :
    • AyncTask requires you to override an abstract method with varargs which is a no no right now in scala Ticket #1459
  • SOLUTION #3
    • Create a java class which extends AsyncTask, I called it MyAsyncTask:
import android.os.AsyncTask;
public abstract class MyAsyncTask<T1,T2,T3> extends AsyncTask<T1,T2,T2>{
	protected T2 doInBackground(T1 ...f) {
		return doInBackground(f[0]);
	}
	abstract protected T2 doInBackground(T1 f);
}

As you can see now doInBackground gets a single argument… which in my current implementation is a Function =)I’ve created an AsyncTask class in scala which extends MyAsyncTask and gets a Function as it’s constructor arg :

class AsyncTask(f:()=>Unit) {
    def doInBackground {
        new _root_.pt.inevo.android.meo.MyAsyncTask[Function0[Unit],Void,Void]  {
           override protected def doInBackground(f: () => Unit):Void = {
               f()
               return null;
           }
          def onProgressUpdate(progress:Int*) { }
         override def  onPostExecute(result:Void) { }
   }.execute(f); 	} }

I also added an implicit to convert from Function into my new AsyncTask class and wrapped it in an object:

object AsyncTask {
     implicit def function2AsyncTask(f: ()=>Unit):AsyncTask=new AsyncTask(f)
}

With this I can simply have regular functions and just call doInBackground:

 val getChannelList = () => {
      for( c <- EPG.getChannelList \\ "Channel" ) {
         Log.v("getChannelList", c \ "Name" text )
}
override def onCreate(savedInstanceState: Bundle) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.main)
      getChannelList.doInBackground
}

I hope this helps some of you get started with Scala on Android. I’ll be working on the layout stuff trying to get ListView and the Adapters to work properly.P.S: I’m using the great DataBinder Dispatch library for Scala to call the service through REST so my Service object is something like:

 object EPG {
    val req = :/("services.sapo.pt") / "EPG"
    def getChannelList=Http(req / "GetChannelList" >> as_xml)
}

where the as_xml function is defined in my XmlParser class as:

def as_xml(res:InputStream) = XmlParser.load(res);

Mobile Platforms thoughts for 2008 3

Nowadays tech junkies have a real problem.. there are just too many cool gadgets to carry around.

The convergence has started and I personally believe that the cell phone will become the “do it all” device of the future. We already have cell phones with decent cameras, PIM software and GPS. Add to this a good storage solution and  you got everything you’ll need on a daily basis.

The problem so far has been the platform. You’ve got Windows Mobile which has been around for a while, still it seems sluggish and is missing the “cool” factor many of us geeks miss… Nokia has the Maemo platform for the N800 which is pretty cool but there is no GSM support. Nokia also has the Symbian OS which allows us to develop in C and Python but it is not compatible with most other manufacturers.  Java has been around for most mobile platforms and there are some pretty decent apps and games but you get the feeling that JAVA is not build right into the platform.. some phones even have a separate JAVA area for you to start your JAVA applications.

Apple has released the sexy iPhone and it is really appealling. Still, the SDK took long to come out and the platform remains too closed for any serious investment in it. Besides that, here in Europe we need 3,5G to have decent Internet access and the iPhone does not provide that.

Then, Google came up with Android. It’s impressive… Google can generate quite a hype around a mobile platform for which there is no hardware yet! This seems to be the way to go.. this way when it arrives at the market there should be lots of cool free software around the web for it, especially with money being offered to the best apps!

Nonetheless Apple’s iPhone still has the sex appeal that most phones only dream of having….

Adobe has been focusing on AIR, Thermo, etc.. they have come up with great technologies for Web and Desktop but delayed the Adobe Flash Lite. Personally I’m not very interested in a stripped down AS2 only Flash version… this could be because they’re hopping the hardware will evolve to support the whole Flash runtime… The actionscript engine uses the TamarinVM so it should be ported to most of mainstreammobile platforms soon.

Well, this post is becoming too long, I just though i’d write here my 2 cents. I’ll be keeping and eye on Google’s Android and the iPhone.. wouldn’t it be a beautiful mariage?