Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Building native Android applications with Mirah and Pindah


Published on

So you want to build native Android applications without using Java? Here's how.

Published in: Technology, Education
  • Be the first to comment

Building native Android applications with Mirah and Pindah

  1. 1. So you want to build Android apps… without Java?<br />Nick Plante @zapnap<br />(A brief introduction to Mirah and Pindah)<br />
  2. 2. Who?<br />Nick Plante<br />(not a Java developer)<br />Zerosum Labs<br />Rails Rumble<br /><br />Chinaccelerator<br />Contact me!<br />@zapnap on Twitter<br /><br />
  3. 3. Why?<br />Because you’re a Ruby developer (familiarity).<br />Because Android is awesome.<br />Because simplicity is elegance.<br />“Think Different.”<br />
  4. 4. Java vs Ruby<br />Dynamic vs Static<br />Simplicity vs Complexity & Verbosity<br />Less Ceremony<br />Java is a systems programming language, after all<br />But… The JVM is an awesome platform<br />Android’s use of the JVM (Dalvik) gives us options<br />
  5. 5. Java Alternatives<br />Android Scripting Environment (SL4A)<br />Great for scripting; not great for applications<br />Limited access to Android API / GUI<br />Performance issues<br />Other JVM-based languages:<br />Scala<br />Clojure<br />JRuby<br />Mirah<br />Groovy?<br />
  6. 6. JRuby & MrRuboto<br />Ruboto is your friend!<br />JRuby interface / framework for Android APIs<br /><br />But JRuby runtime overhead is a problem<br />Slow startup (~10 seconds)<br />Large APK size<br />HelloWorld: 3.4MB compressed, 10MB installed<br />
  7. 7. Introducing Mirah<br />Mirah compiles straight to Java bytecode<br />Very fast, no extra overhead<br />Syntax is very Ruby-ish<br />Statically-typed with local type inference<br />“Ruby with type annotations”<br />No runtime library<br />Mix and match Java code<br />
  8. 8.
  9. 9. Warning!<br />Mirah is still a very young language (v0.0.7)<br />Tooling is very, very alpha<br />Advantage: Eclipse (Java)<br />Redcar looks promising<br />Compilation errors are very, very not-so-fun<br />NativeException: jmeta.SyntaxError: expected Ensure before ' { |a b| Inte' (at line: 16, char: 40)<br />
  10. 10. One thing at a time<br />We’ll get to Android in just a second<br />First let’s see some basic Mirah syntax…<br />
  11. 11. # fib.mirah<br />def fib(a:int):int<br /> if a < 2<br /> a<br /> else<br /> fib(a-1) + fib(a-2)<br /> end<br />end<br />puts fib(20)<br />Ruby vsMirah<br />Parameter type declaration???<br />SRSLY? <br /># fib.ruby<br />def fib(a)<br /> if a < 2<br /> a<br /> else<br /> fib(a-1) + fib(a-2)<br /> end<br />end<br />puts fib(20)<br />Return type can often be inferred.<br />
  12. 12. .class output<br />Produces a java .class<br />$ mirahcfib.mirah<br />public static intfib(int)<br />Can also produce .java code<br />$ mirahc -jfib.mirah<br />* I have no idea why you would want to do this.<br />
  13. 13. .to_java => “ick”<br />// Generated from hello.mirah<br />public class Hello extends java.lang.Object {<br />public static void main(java.lang.String[] argv) {<br /> temp$1 = java.lang.System.out;<br /> temp$1.println(Hello.fib(20));<br /> }<br /> public static intfib(int a) {<br /> return (a < 2) ? (a) : ((Hello.fib((a - 1)) + Hello.fib((a - 2))));<br /> }<br />}<br />
  14. 14. Challenges / Major Differences<br />Java stdlib: both a blessing and a curse<br />List, HashMap, etc<br />arr.get(1) vs arr[0]<br />Blocks work, but syntactic sugar required<br />For example, List#eachcan be used (array)<br />But HashMap#eachdoes not exist<br />No optional arguments, no *splats, no ranges<br />
  15. 15. Using Java’s Standard Library<br />import java.util.Collections<br />import java.util.HashMap<br />import java.util.List<br />class ListPrinter<br /> def print(list:List)<br /> puts "first item: #{list.get(0)}"<br />list.each do |item|<br /> puts "item: #{item}"<br /> end <br /> end <br />end<br />class HashPrinter<br /> def print(map:HashMap)<br />map.keySet.each do |key|<br /> puts "#{key}: #{map.get(key)}"<br /> end <br /> end <br />end<br />map = { 'batman' => 'brucewayne', 'superman' => 'clarkkent' }<br /><br />list = ['peter', 'stewie', 'brian']<br /><br />
  16. 16. Get Mirah<br /># Install JRuby 1.6 if you haven’t already<br /># (or rvm use jruby)<br />$ jruby –S gem install mirah<br />$ mirah-e "puts 'hello world'”<br />> hello world<br />
  17. 17. Now What?<br />
  18. 18. Get the Android SDK<br />Download and install it:<br /><br />Notes on building from the command line: <br /><br />Set up your environment (see above):<br />Make sure to set JAVA_HOME, CLASSPATH, and put your platform-tools directory in your path<br />
  19. 19. Android SDK / Virtual Devices<br />
  20. 20. The anatomy of a typical Android application<br />Activities<br />Intents<br />Manifest File<br />XML Layouts (Views)<br />Services<br />Content Providers<br />(Lots to learn)<br />
  21. 21. Hello Pindah<br />Garrett, Protoform, Mirahndroid => Pindah<br />Goals<br />Make it easy to get started with Android + Mirah<br />Make day to day development tasks easier<br />Provide project structure and conventions<br />Application skeleton generator<br />Rake tasks to hide Ant nastiness<br />Because XML is pain<br />Use Rake to compile / debug / install / etc<br />
  22. 22. What Pindah Does NOT Do<br />No “pretty” wrappers for Android APIs<br />You must learn the APIs to work effectively<br />Does not provide alternatives to XML-based Manifest or view layouts<br /><br />
  23. 23. Get Pindah<br /># For more information, see<br />#<br />$ jruby –S gem installpindah<br /># Generate an Android application skeleton<br />$pindahcreate org.example.hello [/path/to/hello_world] [HelloActivity]<br />
  24. 24. Android App Skeleton<br />├── AndroidManifest.xml<br />├── Rakefile<br />├── libs<br />├── res<br />│   ├── drawable-hdpi<br />│   │   └── ic_launcher.png<br />│   ├── drawable-ldpi<br />│   │   └── ic_launcher.png<br />│   ├── drawable-mdpi<br />│   │   └── ic_launcher.png<br />│   ├── layout<br />│   │   └── main.xml<br />│   └── values<br />│   └── strings.xml<br />└── src<br /> └── org<br /> └── example<br /> └── hello<br /> └── HelloActivity.mirah<br />Managed for you by Pindah:<br /><ul><li>
  25. 25.
  26. 26.
  27. 27. build.xml</li></li></ul><li>Pindah Rake Tasks<br />$ rake -T<br />Android SDK Tools Revision 8<br />Project Target: Android 2.1-update1<br />API level: 7<br />------------------<br />Resolving library dependencies:<br />No library dependencies.<br />------------------<br />Importing rules file: tools/ant/main_rules.xml<br />rake clean # Removes output files created by other targets.<br />rake compile # Compiles project's .mirah files into .class files<br />rake debug # Builds the application and signs it with a debug key.<br />rake install # Installs/reinstalls the debug package onto a running ...<br />rake javac # Compiles and other gen/ files.<br />rake logcat # Tail logs from a device or a device or emulator<br />rake release # Builds the application.<br />rake spec # Print the project spec<br />rake uninstall # Uninstalls the application from a running emulator or dev...<br />
  28. 28. Android Activity Boilerplate<br /># HelloActivity.mirah<br />package org.example.hello<br />import<br />class HelloActivity < Activity<br /> def onCreate(state)<br /> super state<br />setContentViewR.layout.main<br /> end<br />end<br />#<br />package org.example.hello;<br />import;<br />public class HelloActivity<br /> extends Activity<br />{<br /> /** Called when the activity is first created. */<br /> @Override<br /> public void onCreate(<br /> Bundle savedInstanceState)<br /> {<br />super.onCreate(<br />savedInstanceState);<br />setContentView(<br />R.layout.main);<br /> }<br />}<br />
  29. 29. Running the Example App<br />$ cdhello_world<br />$ rake install<br />=> WIN.<br />
  30. 30. Well, that was boring<br />
  31. 31. Slightly More Interesting<br />More expressive code == visible improvement<br />Example application<br />“Up or Down?” website testing app<br /><br />Questions:<br />What do Android callbacks look like?<br />How do I leverage 3rd party (Java) libraries?<br />How do I handle exceptions?<br />How does Mirah deal with scope? (it’s weird)<br />
  32. 32. Up or Down? Down or Up?<br />
  33. 33. Android Listeners (Java)<br />// Sample button click listener in Java<br />// Create an anonymous implementation of OnClickListener<br />private OnClickListenermClickListener = new OnClickListener() {<br /> public void onClick(Viewv) {<br /> // handle click event<br /> }<br />};<br />protected void onCreate(BundlesavedValues) {<br /> ...<br /> // Capture our button from layout<br /> Button mSubmit = (Button)findViewById(;<br /> // Register the onClick listener with theimpl above<br />mSubmit.setOnClickListener(mClickListener);<br /> ...<br />}<br />
  34. 34. StatusActivity + Listeners<br />class StatusActivity < Activity<br /> def onCreate(state)<br /> super state<br />setContentViewR.layout.main<br /> @url = EditTextfindViewById(<br />@submit = Button findViewById(<br />setListeners<br />end<br /> def setListeners<br /> this = self<br /> # SHORTCUT: click listener must implement onClick<br /> @submit.setOnClickListener do |v|<br /> status = this.checkSiteStatus(this.getUrl)<br />this.showResult status<br /> end<br /> end<br />Scoping for ivars and self is incomplete. Assign a local var within scope.<br />Easy to add anonymous listeners with this syntax (implements a single method interface)<br />
  35. 35. Using External Java Libraries<br />Put jars in libs folder and import to use. Simple! (must import Android libs too)<br />import<br />import<br />import org.jsoup.Jsoup<br />import org.jsoup.nodes.Document<br />def checkSiteStatus(address:String):String<br />return "Please specify a URL to test" if address.equals('')<br />begin<br />doc = Jsoup.connect(<br /> "" + address<br /> ).get<br />res ="#container").first.text<br />Log.d 'StatusActivity',<br /> 'Full response from server is: ' + res<br />res.substring(0, res.indexOf('Check another'))<br />rescue SocketTimeoutException => ex<br />"Unable to contact the server. How ironic!”<br />end<br />end<br />Exception handling works like it does in Ruby. Must import specific exceptions.<br />
  36. 36. Wrapping Up: Dialog Example<br />def getUrl<br />@url.getText.toString<br />end<br />def showResult(message:String)<br />alert =<br />alert.setTitle 'Site Test Results’<br />alert.setMessage message<br />alert.setPositiveButton('OK') do |dialog, w|<br />dialog.dismiss<br />end<br /><br />end<br />
  37. 37. Android XML Layouts (main.xml)<br /><?xml version="1.0" encoding="utf-8"?><br /><RelativeLayoutxmlns:android=""<br />android:orientation="vertical"<br />android:layout_width="fill_parent"<br />android:layout_height="fill_parent"><br /> <LinearLayout<br />android:orientation="vertical"<br />android:layout_width="fill_parent"<br />android:layout_height="wrap_content"><br /> <TextView<br />android:layout_width="fill_parent"<br />android:layout_height="wrap_content"<br />android:gravity="center_horizontal"<br />android:textSize="20sp"<br />android:textStyle="bold"<br />android:text="@string/app_title" /><br /> <TextView<br />android:layout_width="fill_parent"<br />android:layout_height="wrap_content"<br />android:gravity="center_horizontal"<br />android:textSize="18sp"<br />android:textStyle="bold"<br />android:layout_marginBottom="10dip"<br />android:text="@string/app_subtitle" /><br /> <EditTextandroid:id="@+id/url_txt"<br />android:layout_width="fill_parent"<br />android:singleLine = "true"<br />android:layout_height="wrap_content"<br />android:inputType="textUri"<br />android:hint="@string/url_example" /><br /> <Button android:id="@+id/submit_btn"<br />android:layout_width="140dip"<br />android:layout_marginTop="6dip"<br />android:layout_height="wrap_content"<br />android:layout_gravity="center"<br />android:gravity="center"<br />android:text="@string/submit_btn" /><br /> </LinearLayout><br /> <TextView<br />android:layout_width="fill_parent"<br />android:layout_height="wrap_content"<br />android:gravity="center_horizontal"<br />android:layout_alignParentBottom="true"<br />android:autoLink="web"<br />android:text="@string/powered_by" /><br /></RelativeLayout><br /><EditTextandroid:id="@+id/url_txt"<br />android:layout_width="fill_parent"<br />android:singleLine = "true"<br />android:layout_height="wrap_content"<br />android:inputType="textUri"<br />android:hint="@string/url_example" /><br />more info<br />app title<br />[ url input ]<br />[ button]<br />
  38. 38. One More Thing<br />Android Manifest lists top-level activities and required permissions<br />Our app requires Internet access<br />Add the permission to AndroidManifest.xml:<br /><uses-permission android:name="android.permission.INTERNET" /><br />
  39. 39. It Works!<br />
  40. 40. Ideas for Next Steps<br />Implement a ProgressDialog<br />And perform the site check in an AsyncTask<br />Record a log of website test history to a ListView<br />Allow users to browse test history through a separate Activity<br />Store test history to a local Sqlite database (and ListAdapter)<br />Fork me at <br /><br />
  41. 41. Conclusions (or lack thereof)<br />Mirah is a nice midpoint between Ruby and Java<br />Well-suited for Dalvik JVM work<br />But still very immature / not yet practical for daily use<br />Opportunity to help push mobile dev forward<br />Lack of good IDE support<br />Makes working with the (massive) Android API difficult<br />Debugging is a pain in the butt<br />ADB (Rake logcat) is incredibly useful; learn to use it<br />I personally still prefer mobile web development ;-) but sometimes native is the way to go!<br />
  42. 42. And so it goes<br />Mirah Language Resources<br /><br /><br />Pindah and Mirah and Android Oh My!<br /><br /> (experiments)<br /> (urbanspoon)<br /><ul><li>General Android Development
  43. 43.
  44. 44.</li>