Scala on Android Tom Adams @tomjadams
Me • SVP of Polyglot Engineering @ Cogent • Rails, iOS, etc. • Co-Founder & CTO Oomph • 4 shipping + 1 prototype Android app • > 100 bespoke iOS apps • ~250 iOS apps on Oomph platform • Enterprise Java, HPC, “big data” background • Founder of BFPG
What? • Experiences building a native Android app • Oomph Viewer, Subaru Symmetry, etc. • Not looking at Phonegap, Ximian, Titanium, etc. • Not looking at “non-Scala” problems • Not teaching you Scala • Lots of code, the deck will be available
App Goals • Oomph - digital publishing, think mags on iPads • A technical proof of concept client for Android • Build as a platform not a single app • Develop in parallel with server • No Java • Take advantage of Scala language & library support
The Good
Why Scala? • Had done Java before, don’t want to use again • “Better Java” • Succinct/less boilerplate - closures, type classes, type aliases, type inference, no semi-colons, no ‘.’ • Features - immutability, equational reasoning, functions, case classes, implicits, packages, mixins, currying/partial application, etc. • Standard & other library support - option, either, future, etc. • Cool stuff! scalaz, actors, higher-kinds, etc. • Share concepts/code/DB schema with server • Monadic code FTW!
Example 1 - Java context . runOnUiThread (new ¡ Runnable() ¡ { ¡ ¡ ¡@Override ¡ ¡ ¡ public ¡ void ¡ run() ¡ { ¡ ¡ ¡ ¡ ¡dialog . dismiss (); ¡ ¡ ¡ ¡ ¡String ¡standaloneStartUrl ¡ = ¡"file://" ¡ + ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡context . getFilesDir() ¡ + ¡"/content/index.html" ; ¡ ¡ ¡ ¡ ¡Intent ¡next ¡ = ¡ new ¡ Intent( context , ¡IssueViewerActivity . class ); ¡ ¡ ¡ ¡ ¡next . putExtra ( "start_url" , ¡standaloneStartUrl ); ¡ ¡ ¡ ¡ ¡context . startActivity ( next ); ¡ ¡ ¡ ¡ ¡context . finish (); ¡ ¡ ¡ } ¡ });
Example 1 - Scala context . runOnUiThread ¡ { ¡ ¡ ¡dialog . dismiss () ¡ ¡ ¡ val ¡standaloneStartUrl ¡ = ¡"file://" ¡ + ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡context . getFilesDir ¡ + ¡"/content/index.html" ¡ ¡ ¡ val ¡next ¡ = ¡ new ¡ Intent( context , ¡classOf [IssueViewerActivity]) ¡ ¡ ¡next . putExtra ( "start_url" , ¡standaloneStartUrl ) ¡ ¡ ¡context . startActivity ( next ) ¡ ¡ ¡context . finish () ¡ }
Example 2 - Java Button ¡button ¡ = ¡ new ¡ Button( context ); ¡ button . setText ( "Greet" ); ¡ button . setOnClickListener (new ¡ OnClickListener() ¡ { ¡ ¡ ¡@Override ¡ ¡ ¡public ¡void ¡onClick(View ¡v) ¡{ ¡ ¡ ¡ ¡ ¡ Toast. makeText ( ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ context , ¡"Hello!" , ¡ Toast.LENGTH_SHORT). show (); ¡ ¡ ¡ } ¡ }); ¡ layout . addView ( button );
Example 2 - Scala val ¡button ¡ = ¡ new ¡ Button( context ) ¡ button . setText ( "Greet" ) ¡ button . setOnClickListener (new ¡ OnClickListener() ¡ { ¡ ¡ ¡ def ¡onClick ( v : ¡ View) ¡ { ¡ ¡ ¡ ¡ ¡ Toast. makeText ( ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ context , ¡"Hello!" , ¡ Toast.LENGTH_SHORT). show () ¡ ¡ ¡ } ¡ }) ¡ layout . addView ( button )
Example 2 - Scala val ¡button ¡ = ¡ new ¡ Button( context ) ¡ button . setText ( "Greet" ) ¡ button . setOnClickListener ( Toast.makeText( ¡ ¡ ¡ ¡ ¡ context , ¡"Hello!" , ¡ Toast.LENGTH_SHORT). show ()) ¡ layout . addView ( button )
Example 2 - Scala(OID) SButton( "Greet" , ¡toast ( "Hello!" ))
Example 2 - Scala(OID) SButton( "Greet" , ¡toast ( "Hello!" ))
Objections • “Functions slow down VM” • “Too many small classes” • Not a problem in practice (YMMV) • Can proguard away • Language issues…
Scala ≈ swift
Toolchain • sbt • Android Plugin [1] • Scalastyle - stylechecker • IntelliJ w/ Scala plugin • TeamCity [1] https://github.com/pfn/android-sdk-plugin
sbT • “Simple” build tool • Native Scala build tool • Not great, but better than alternatives • Supported by TypeSafe
sbt Plugin • Most mature at the time • Requires giter8 • All the things you’d need: emulator & device support, signing, tests, etc.
IntelliJ
IntelliJ • Awesome IDE • Multiple platforms - RubyMine, AppCode, PHP Storm, etc. • Familiar • Decent support for Scala & sbt
Other choices • Eclipse (?) • Android Studio (IntelliJ) • Android SDK Plugin [1] • Scaloid template [2] (uses [1]) [1] https://github.com/pfn/android-sdk-plugin [2] https://github.com/pocorall/hello-scaloid-sbt
Scaloid • Take advantage of language features • Simplifies common patterns • Alerts, inter-activity comms • DSL for UI building
Scaloid var ¡connectivityListener : ¡ BroadcastReceiver ¡ = ¡ null ¡ � def ¡onResume () ¡ { ¡ ¡ ¡ super. onResume () ¡ ¡ ¡connectivityListener ¡ = ¡ new ¡ BroadcastReceiver ¡ { ¡ ¡ ¡ ¡ ¡ def ¡onReceive ( context : ¡ Context, ¡intent : ¡ Intent) ¡ { ¡ ¡ ¡ ¡ ¡ ¡doSomething () ¡ ¡ ¡ ¡ ¡ } ¡ ¡ ¡ } ¡ ¡ ¡ ¡registerReceiver ( connectivityListener , ¡ ¡ ¡ ¡ ¡ ¡ ¡ new ¡ IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)) ¡ } ¡ � def ¡onPause () ¡ { ¡ ¡ ¡unregisterReceiver ( connectivityListener ) ¡ ¡ ¡ super. onPause () ¡ }
Scaloid broadcastReceiver (ConnectivityManager.CONNECTIVITY_ACTION) ¡ { ¡ ¡ ¡ ( context , ¡intent ) ¡ => ¡doSomething () ¡ }
Scaloid new ¡ AsyncTask[String , ¡ Void , ¡ String] ¡ { ¡ ¡ ¡ def ¡doInBackground ( params : ¡ Array[String]) ¡ = ¡ { ¡ ¡ ¡ ¡ ¡doAJobTakeSomeTime ( params ) ¡ ¡ ¡ } ¡ � ¡ ¡ override ¡ def ¡onPostExecute ( result : ¡ String) ¡ { ¡ ¡ ¡ ¡ ¡alert ( "Done!" , ¡result ) ¡ ¡ ¡ } ¡ }. execute ( "param" )
Scaloid Future ¡ { ¡ ¡ ¡ val ¡result ¡ = ¡doAJobTakeSomeTime ( params ) ¡ ¡ ¡runOnUiThread ( alert ( "Done!" , ¡result )) ¡ }
scalaz • An extension to the core Scala library for functional programming • New datatypes (Validation, NonEmptyList, etc.) • Extensions to standard classes (OptionOps, ListOps, etc.) • Implementations of general functions you need (ad-hoc polymorphism, traits + implicits)
Argonaut val ¡input ¡ = ¡""" ¡ ¡ ¡[ ¡ ¡ ¡ ¡ ¡{ ¡"name": ¡"Mark", ¡"age": ¡191 ¡}, ¡ ¡ ¡ ¡ ¡{ ¡"name": ¡"Fred", ¡"age": ¡33, ¡"greeting": ¡"hey ¡ho, ¡lets ¡go!" ¡}, ¡ ¡ ¡ ¡ ¡{ ¡"name": ¡"Barney", ¡"age": ¡35, ¡"address": ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡"street": ¡"rock ¡street", ¡"number": ¡10, ¡"post_code": ¡2039 ¡ ¡ ¡ ¡ ¡}} ¡ ¡ ¡] ¡ """ ¡ ¡ ¡ val ¡people ¡ = ¡input . decodeOption [List[Person]]. getOrElse (Nil) ¡ ¡ ¡ val ¡nice ¡ = ¡people . map ( person ¡ => ¡ ¡ ¡ ¡ ¡person . copy ( greeting ¡ = ¡person . greeting . orElse (Some( "Hello ¡good ¡sir!" )))) ¡ ¡ ¡ val ¡result ¡ = ¡nice . asJson ¡ println ( result . spaces4 ) ¡ ¡ ¡ assert ( result . array . exists (_. length ¡ == ¡3 ))
Specs2 final ¡ class ¡ HelloWorldSpec ¡ extends ¡ Specification ¡ { ¡ ¡ ¡"The ¡'Hello ¡world' ¡string" ¡should ¡ { ¡ ¡ ¡ ¡ ¡"contain ¡11 ¡characters" ¡in ¡ { ¡ ¡ ¡ ¡ ¡ ¡ ¡"Hello ¡world" ¡must ¡have ¡size ( 11 ) ¡ ¡ ¡ ¡ ¡ } ¡ ¡ ¡ ¡ ¡"start ¡with ¡'Hello'" ¡in ¡ { ¡ ¡ ¡ ¡ ¡ ¡ ¡"Hello ¡world" ¡must ¡startWith ( "Hello" ) ¡ ¡ ¡ ¡ ¡ } ¡ ¡ ¡ ¡ ¡"end ¡with ¡'world'" ¡in ¡ { ¡ ¡ ¡ ¡ ¡ ¡ ¡"Hello ¡world" ¡must ¡endWith ( "world" ) ¡ ¡ ¡ ¡ ¡ } ¡ ¡ ¡ } ¡ }
Slick • Type safe DB access library for Scala • Supported by TypeSafe • Works well on device or server • Had used in several projects before (ScalaQuery) • Added in integration with Android DB lifecycle • Added migration support
Slick class ¡ Coffees( tag : ¡ Tag) ¡ ¡ ¡ ¡ ¡ ¡ extends ¡ Table[(String , ¡ Double)]( tag , ¡"COFFEES" ) ¡ { ¡ ¡ ¡ def ¡name ¡ = ¡column [String]( "COF_NAME" , ¡O .PrimaryKey) ¡ ¡ ¡ def ¡price ¡ = ¡column [Double]( "PRICE" ) ¡ ¡ ¡ def ¡ * ¡ = ¡ ( name , ¡price ) ¡ } ¡ ¡ ¡ val ¡coffees ¡ = ¡ TableQuery[Coffees] ¡ coffees . map (_. name ) ¡ coffees . filter (_. price ¡ < ¡10.0 ) ¡ val ¡coffeeNames : ¡ Seq[Double] ¡ = ¡coffees . map (_. price ). list ¡ coffees . filter (_. price ¡ < ¡10.0 ). sortBy (_. name ). map (_. name )
Google • Access to the infrastructure Google provide • https://www.buzzingandroid.com/2013/01/ push-messages-on-android-and-iphone/
Recommend
More recommend