$30 off During Our Annual Pro Sale. View Details »

Scala on Android - The current state of affairs

Scala on Android - The current state of affairs

An overview of the current state of affairs when developing Android apps with Scala, and examine why contrary to popular belief it is ready for prime time. We will discover some of the tools and more useful libraries, and explore how Scala on Android helps circumvent most of the limitations of Java and the Android SDK

Raúl Raja Martínez

March 10, 2015
Tweet

More Decks by Raúl Raja Martínez

Other Decks in Programming

Transcript

  1. (Scala on Android) 㱺 The current state of affairs 1

    View Slide

  2. whoami
    㱺 CTO & Co-Founder at 47 Degrees, a global
    consulting agency & Typesafe Consulting Partner.
    @raulraja
    @47deg
    http://47deg.com/blog
    (Scala on Android) 㱺 The current state of affairs 2

    View Slide

  3. Build Tools
    (Scala on Android) 㱺 The current state of affairs 3

    View Slide

  4. SBT 㱺 Android SDK Plugin
    https://github.com/pfn/android-sdk-plugin
    (Scala on Android) 㱺 The current state of affairs 4

    View Slide

  5. SBT 㱺 Android SDK Plugin
    — Supports all Android SDK tasks
    — dex
    — typedResourcesGenerator
    — proguard
    — buildConfigGenerator
    — (+ 20... more)
    (Scala on Android) 㱺 The current state of affairs 5

    View Slide

  6. SBT 㱺 Android SDK Plugin 㱺 typedResourcesGenerator
    object TR {
    val title = TypedResource[TextView](R.id.title)
    object layout {
    val abc_screen_toolbar = TypedLayout[ActionBarOverlayLayout](R.layout.abc_screen_toolbar)
    }
    }
    class MyActivity extends TypedActivity {
    val titleTextView = findView(title) //titleTextView inferred as TextView, no casting needed
    }
    (Scala on Android) 㱺 The current state of affairs 6

    View Slide

  7. SBT 㱺 Android SDK Plugin 㱺 proguard
    Size Matters
    Scala byte code size reduced ~ (2.8M)
    (Scala on Android) 㱺 The current state of affairs 7

    View Slide

  8. SBT 㱺 Android SDK Plugin
    — https://github.com/pfn/android-sdk-plugin
    — Active
    — Fast (incremental compilation and proguard
    caching)
    — Proguard + MultiDexApplication integration
    (Circumvents 65K method limit)
    — Supports AAR, JAR and APK artifact types
    (Scala on Android) 㱺 The current state of affairs 8

    View Slide

  9. IDE Support
    (Scala on Android) 㱺 The current state of affairs 9

    View Slide

  10. IntelliJ IDEA 㱺 Syntax Highlighting
    (Scala on Android) 㱺 The current state of affairs 10

    View Slide

  11. IntelliJ IDEA 㱺 Android + Scala + SBT
    (Scala on Android) 㱺 The current state of affairs 11

    View Slide

  12. IntelliJ IDEA
    — Active
    — Syntax Highlighting
    — Code assistance
    — Android Studio : Based on IntelliJ
    > Google says: If you have been using Eclipse
    with ADT, be aware that Android Studio is now the
    official IDE for Android
    (Scala on Android) 㱺 The current state of affairs 12

    View Slide

  13. Libraries
    (Scala on Android) 㱺 The current state of affairs 13

    View Slide

  14. Libraries 㱺 Scaloid 㱺 Simplifying the Android SDK
    //plain vanilla 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)
    (Scala on Android) 㱺 The current state of affairs 14

    View Slide

  15. Libraries 㱺 Scaloid 㱺 Simplifying the Android SDK
    //with Scaloid
    SButton("Greet", toast("Hello!"))
    (Scala on Android) 㱺 The current state of affairs 15

    View Slide

  16. Libraries 㱺 Scaloid 㱺 XML-less layouts
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content" android:padding="20dip">
    android:layout_height="wrap_content" android:text="Sign in"
    android:layout_marginBottom="25dip" android:textSize="24.5sp"/>
    android:layout_height="wrap_content" android:text="ID"/>
    android:layout_height="wrap_content" android:id="@+id/userId"/>
    android:layout_height="wrap_content" android:text="Password"/>
    android:layout_height="wrap_content" android:id="@+id/password"
    android:inputType="textPassword"/>
    android:layout_height="wrap_content" android:id="@+id/signin"
    android:text="Sign in"/>

    (Scala on Android) 㱺 The current state of affairs 16

    View Slide

  17. Libraries 㱺 Scaloid 㱺 XML-less layouts
    //with scaloid
    new SVerticalLayout {
    STextView("Sign in").textSize(24.5 sp).<<.marginBottom(25 dip).>>
    STextView("ID")
    SEditText()
    STextView("Password")
    SEditText() inputType TEXT_PASSWORD
    SButton("Sign in")
    }.padding(20 dip)
    (Scala on Android) 㱺 The current state of affairs 17

    View Slide

  18. Libraries 㱺 Scaloid 㱺 Futures & Async
    //plain scala
    new AsyncTask[String, Void, String] {
    def doInBackground(params: Array[String]) = {
    doAJobTakeSomeTime(params)
    }
    override def onPostExecute(result: String) {
    alert("Done!", result)
    }
    }.execute("param")
    (Scala on Android) 㱺 The current state of affairs 18

    View Slide

  19. Libraries 㱺 Scaloid 㱺 Futures & Async
    //scaloid
    Future {
    val result = doAJobTakeSomeTime(params)
    runOnUiThread(alert("Done!", result))
    }
    (Scala on Android) 㱺 The current state of affairs 19

    View Slide

  20. Libraries 㱺 Macroid 㱺 Functional UI with Macros
    import macroid._
    import macroid.FullDsl._
    class GreetingActivity extends Activity with Contexts[Activity] {
    override def onCreate(savedInstanceState: Bundle) = {
    super.onCreate(savedInstanceState)
    // the layout goes here
    setContentView {
    getUi {
    l[LinearLayout](
    w[Button],
    w[TextView]
    )
    }
    }
    }
    }
    (Scala on Android) 㱺 The current state of affairs 20

    View Slide

  21. Libraries 㱺 Macroid 㱺 UI composition
    // ActivityContext is an Android Context obtained from an Activity
    import macroid.ActivityContext
    ...
    def layout1(implicit ctx: ActivityContext) =
    l[LinearLayout](
    w[TextView]
    )
    def layout2(implicit ctx: ActivityContext) =
    l[FrameLayout](
    w[ProgressBar]
    )
    def layout3(implicit ctx: ActivityContext) =
    l[FrameLayout](
    layout1,
    layout2
    )
    ...
    (Scala on Android) 㱺 The current state of affairs 21

    View Slide

  22. Libraries 㱺 Macroid 㱺 Tweaks
    l[LinearLayout](
    // set button caption
    w[Button] <~ text("Click me"),
    // set text and hide for the time being
    w[TextView] <~ text("Hello!") <~ hide
    // set layout orientation
    ) <~ vertical
    (Scala on Android) 㱺 The current state of affairs 22

    View Slide

  23. Libraries 㱺 Macroid 㱺 Tweaks Composition
    // AppContext is an Android Context obtained from getApplicationContext
    import macroid.AppContext
    // More tweaks
    import macroid.contrib.TextTweaks
    def greeting(greeting: String)(implicit appCtx: AppContext) =
    TextTweaks.large +
    text(greeting) +
    hide
    (Scala on Android) 㱺 The current state of affairs 23

    View Slide

  24. Libraries 㱺 Macroid 㱺 Events
    button <~ On.click {
    ...
    }
    (Scala on Android) 㱺 The current state of affairs 24

    View Slide

  25. Libraries 㱺 Macroid 㱺 Slots
    // create a slot
    var greeting = slot[TextView]
    l[LinearLayout](
    w[TextView] <~
    // wire the view to the slot
    wire(greeting) <~
    OurTweaks.greeting("Hello!"),
    w[Button] <~
    text("Click me") <~
    On.click {
    // use the slot elsewhere
    greeting <~ show
    }
    ) <~ vertical
    (Scala on Android) 㱺 The current state of affairs 25

    View Slide

  26. Libraries 㱺 Macroid 㱺 Contexts
    class MyActivity extends Activity with Contexts[Activity] {
    // implicit access to AppContext & ActivityContext stored as a weak reference
    }
    class MyFragment extends Fragment with Contexts[Fragment] {
    // implicit access to AppContext & ActivityContext stored as a weak reference
    }
    (Scala on Android) 㱺 The current state of affairs 26

    View Slide

  27. Libraries 㱺 Macroid 㱺 Contexts
    class MyActivity extends Activity with Contexts[Activity] {
    // implicit access to AppContext & ActivityContext stored as a weak reference
    }
    class MyFragment extends Fragment with Contexts[Fragment] {
    // implicit access to AppContext & ActivityContext stored as a weak reference
    }
    No need to explicitly pass the context around!
    (Scala on Android) 㱺 The current state of affairs 27

    View Slide

  28. Libraries 㱺 Macroid 㱺 Snails
    val focusLoudly = Snail[View] { view 㱺
    view.setFocus()
    playSound
    }
    (Scala on Android) 㱺 The current state of affairs 28

    View Slide

  29. Libraries 㱺 Macroid 㱺 Snails composition
    val wink = fadeIn ++ fadeOut
    (Scala on Android) 㱺 The current state of affairs 29

    View Slide

  30. Libraries 㱺 Macroid 㱺 Snails & Tweaks combined
    editText <~ text("foo") <~~ fadeIn <~ enable
    (Scala on Android) 㱺 The current state of affairs 30

    View Slide

  31. Libraries 㱺 Macroid 㱺 Easy workflows
    (myProgressBar <~~ fadeOut(400)) ~~
    (myTextView <~~ blink) ~~
    (myOtherTextView <~ text("’Scala at the Sea!"))
    (Scala on Android) 㱺 The current state of affairs 31

    View Slide

  32. Libraries 㱺 Macroid 㱺 Transformers
    linearLayout <~ Transformer {
    case t: TextView 㱺 t <~ text("foo")
    case i: ImageView 㱺 i <~ hide
    }
    (Scala on Android) 㱺 The current state of affairs 32

    View Slide

  33. Libraries 㱺 Macroid 㱺 Adaptive (Media queries)
    object OurTweaks {
    def orient(implicit appCtx: AppContext) =
    landscape ? horizontal | vertical
    }
    ...
    // in layout
    l[LinearLayout](
    ...
    ) <~ OurTweaks.orient
    (Scala on Android) 㱺 The current state of affairs 33

    View Slide

  34. Libraries 㱺 Macroid 㱺 Viewable
    Brings the power of Typeclasses to UI composition.
    How to display A using W.
    libraryDependencies += aar("org.macroid" %% "macroid-viewable" % "2.0.0-M3")
    trait Viewable[A, +W <: View]
    (Scala on Android) 㱺 The current state of affairs 34

    View Slide

  35. Libraries 㱺 Macroid 㱺 Viewable
    import macroid.viewable.Viewable
    case class User(name: String)
    def userViewable(
    implicit ctx: ActivityContext,
    appCtx: AppContext): Viewable[User, TextView] =
    Viewable[User] { user 㱺
    w[TextView] <~ TextTweaks.large <~ text(user.name)
    }
    (Scala on Android) 㱺 The current state of affairs 35

    View Slide

  36. Libraries 㱺 Macroid 㱺 Akka Fragments
    Handling Fragment events & messaging with Actors.
    class MyActor extends FragmentActor[MyFragment] {
    def receive = receiveUi andThen {
    case MyMessage(x) 㱺 ...
    case MyOtherMessage 㱺 withUi(fragment 㱺 Ui {
    // do some cool ui stuff here
    })
    case FragmentActor.AttachUi(_) 㱺 ...
    case FragmentActor.DetachUi(_) 㱺 ...
    }
    }
    (Scala on Android) 㱺 The current state of affairs 36

    View Slide

  37. OS Apps 㱺 Translate Bubble
    https://play.google.com/store/apps/details?id=com.fortysevendeg.translatebubble
    https://github.com/47deg/translate-bubble-android
    (Scala on Android) 㱺 The current state of affairs 37

    View Slide

  38. OS Apps 㱺 Scala Days Official App
    https://play.google.com/store/apps/details?id=com.fortysevendeg.android.scaladays
    https://github.com/47deg/scala-days-android
    (source code available on March 15th)
    (Scala on Android) 㱺 The current state of affairs 38

    View Slide

  39. OS Apps 㱺 Scala API Demos
    https://play.google.com/store/apps/details?id=com.fortysevendeg.scala.android
    https://github.com/47deg/scala-android
    (Scala on Android) 㱺 The current state of affairs 39

    View Slide

  40. Thank you
    @raulraja
    @47deg
    raul at 47deg.com
    http://47deg.com/blog
    https://speakerdeck.com/raulraja/scala-on-android-the-current-state-of-
    affairs
    https://github.com/47deg/scala-on-android-deck
    (Scala on Android) 㱺 The current state of affairs 40

    View Slide