Scala on Android 101 - Proguard, XmlParser and Function2AsyncTask

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);

12 Comments so far

  1. Sebastian Deutsch on November 16th, 2009

    Are you using eclipse in any of that or do you completely abandoned it?

  2. ,..] blog.nelsonsilva.eu is other useful source of information on this topic,..]

  3. Mark Abbott on December 19th, 2009

    Thanks for the info, keep up the Scala-on-Android work!

  4. US Education on January 21st, 2010

    Very enjoyed this! Well done!

  5. bandsxbands on February 2nd, 2010

    Seeing these kind of posts reminds me of just how technology truly is ubiquitous in this day and age, and I am 99% certain that we have passed the point of no return in our relationship with technology.

    I don’t mean this in a bad way, of course! Ethical concerns aside… I just hope that as technology further innovates, the possibility of copying our memories onto a digital medium becomes a true reality. It’s a fantasy that I dream about all the time.

    (Posted on Nintendo DS running R4i SDHC DS ZKwa)

  6. Education site on February 5th, 2010

    of corse you can cry under water,and i pulled flys wings and still called it a fly

  7. warez cracks on February 7th, 2010

    If he doesn’t know what he is doing, mutual fund is the way to go. That might be counted as cheating in the class though.

  8. fast cash payday loan on February 11th, 2010

    I am completely impressed with the article I have just read. I wish the author of blog.nelsonsilva.eu can continue to provide so much useful information and unforgettable experience to blog.nelsonsilva.eu readers. There is not much to say except the following universal truth: At the gym, there’s always someone who nonchalantly walks around naked I will be back.

  9. Refinance on February 26th, 2010

    Benedict, it is a great post thanks for posting it!

  10. Affiliate on March 3rd, 2010

    How can I make money monthly on my investments?

  11. Cheap phentermine. on March 4th, 2010

    Buy cheap phentermine online….

    Buy phentermine online buy cheap phentermine. Cheap phentermine. Cheap phentermine free shipping. Buy cheap phentermine now save. Cheap phentermine c o d payment. Buy cheap phentermine. Cheap phentermine diet pill….

  12. Affiliate Network on March 6th, 2010

    WoW! Thank you very much for that enlightening article

Leave a Reply