2. Who Am I?
Taisuke Oe
GitHub: / Twitter:
My Work
Technical Advisor in Septeni Original, Inc.
Organizing
taisukeoe @OE_uia
BONX Android App
ScalaMatsuri
3. The largest international Scala Conference in Asia.
550-600 participants.
Voting session for CFP.
Travel support for highly voted speakers.
Bi-directional professional translation services.
🍣🍻
Around March next year?
4. This talk Is About:
VoIP client
VoIP stands for Voice Over Internet Protocol
10. What Is BONX ?
Group talk system during outdoor activities
Snowboarding
Skiing
Fishing
Cycling
...
11. BONX Architecture
Apps
VoIP client
Android : Scala
iOS : Objective C / Swift
Servers
API server : Ruby on Rails
Voice server : golang
Earpiece
Special bluetooth headset
13. Stateful Asynchronous Stream
Processing System
VoIP is.
Upstream
Recorder -> some DSP -> Encoder -> Socket
Downstream
Socket -> Decoder -> some DSP -> Player
DSP stands for Digital Signal Processing
Every component has its own state, which is typically thread UNsafe.
14. BONX Must Be Resilient.
In outdoor activities, we must handle a tons of errors:
Poor network
Out of range, and recover from it
Hardware I/O errors
Bluetooth disconnection
If a component has a problem, it has to be recovered.
15. Even Worse
Errors might be discovered in a downstream of root-cause.
Root cause has to be xed.
Errors have to be propagated in reverse.
Broken modules might produce broken audio data.
Broken audio data might spoil user's experience.
It has to be disposed from its queue.
17. That's Where Akka Comes In!
Akka is a toolkit for concurrent programing, resiliency
... and distributed systems (out of scope).
18. for (Stateful) Concurrent Programming
Message driven actor model
An actor encapsulates its state unless it exposes explicitly.
19. Actor with a State Example
class PlayActor() extends Actor {
private val track: AudioTrack = createNewAudioTrack //state. Thread UN-safe
override def preStart(): Unit = track.play()
override def receive: Receive = {
//An actor retrieves and process a message from its mailbox one-at-a-time.
case AudioPacketMessage(content:ByteString) =>
track.write(content.toArray[Byte], 0, content.length)
}
override def postStop(): Unit = {
track.stop()
track.flush()
track.release()
}
}
20. Akka Makes A System Resilient
Because Akka handles exceptions very well.
Actor hierarchy
Restart, Stop or Resume a child actor based on supervisorStrategy
Note: Restart via supervisingStrategy keeps messages in it.
Monitoring (Death watch)
A watcher actor get a Terminated(actorRef) message once a watchee actor
stops.
Note: subsequent recreation of the actor disposes all messages in it.
21. Sample Exception Handling by an Actor
class ExceptionHandlingActor() extends Actor{
private var childActor:ActorRef = createChildActor
override def supervisorStrategy: SupervisorStrategy = OneForOneStrategy(){
//Want to reset all mailboxes
case _:BrokenAudioDataException => Stop
//At default, child actors will be restarted with keeping their mailbox.
case t => super.supervisorStrategy.decider.applyOrElse(t, (_:Any) => Escalate)
}
def receive = {
//Stopped childActor will be recreated.
case Terminated(ref) => if(childActor == ref) {
context.unwatch(childActor)
childActor = createChildActor
}
}
private def createChildActor = {
val c = context.child(ChildActor.props)
context watch c
c
}
}
22. Recaps: How Akka Works Great?
Stateful Concurrent Programming
Actor state encapsulation / Processing a message one-at-a-time without an
explicit lock.
Resiliency
Actor hierarchy or monitoring handles errors as you like.
Akka solves VoIP problems (almost)!
23. Why Do I Say "Almost" ?
Some problems cannot be captured by exceptions.
An audio driver might get silenced sometimes and doesn't respond to
anything.
There is no silver bullet.
Ask a message and check if Ack will be returned within Timeout .
If the Ask gets timeout, stop and re-create a new actor.
Please rst consider if you can capture it as an expcetion.
This heuristic approach is not often recommended.
25. Build Toolchain
scalac compiles Scala source codes into Java bytecodes
dex in Android SDK translates Java bytecode into Dalvik Executable bytecodes
is awesome.
It is almost functionally compatible with android standard build system.
It works great with other sbt-plugins.
scala-android/sbt-android
26. Android Device Specs Are Good Enough
In this couple of years, agship Android devices have:
4 to 10 cores CPU
3 to 4 GB memories
Up to around 512MB memory per VM can be used with largeHeap=true
con guration.
27. Q. Should You Use Scala in Android?
This decision is up to you.
Every technology has trade-o s.
29. Pros
Powerful language features, standard library and ecosystem.
Concurrent programming
Collection API
Algebraic Data Type & Pattern Matching
Traits
Productive
0.5 ~ 1.2 ppl for DevOps and Tuning of BONX Android App for two years.
Smaller context-switch cost between client codes and server codes.
30. Another Android Scala Usecase?
Stateless (except Views) concurrent programming
view modi cation must run on UIThread in Android.
31. Scala Offers Better APIs for Concurent
Programming
Scala standard Future works well.
Use your own ExecutionContext for onComplete, andThen or else.
UIExecutionContext pattern for UIThread callbacks.
32. UIExecutionContext Pattern
class UIExecutionContext(activity:Activity, reporter: Throwable => Unit)
extends ExecutionContext{
def execute(runnable: Runnable): Unit = activity.runOnUiThread(runnable)
def reportFailure(t: Throwable): Unit = reporter(t)
}
Future{
//some heavy calculation
}.onComplete{
case Success(result) => //reflect your result on views
case Failure(exp) => //show error message
}(uiExecutionContext) //Explicitly!
33. Other Android Scala Projects in Real World
Septeni Original
Comic app hits 6 million DLs!
47 Degrees
also has an Akka modules.
GANMA!
47deg/macroid
47deg/nine-cards-v2
47deg/scala-days-android
pocorall/scaloid
34. Cons
Method 64k limit per a dex le.
Scala standard library jar is too big to be a orded as it is.
Proguard or MultiDex must be used.
No Java8 support yet
Android SDK toolchain still targets Java6+ environment.
Akka version has to be 2.3.16, which is marked End-of-Life.
You have to be careful for wasting memories.
No o cial support by Google nor Lightbend (unlike Kotlin)
35. Proguard
Proguard removes unused classes, elds and methods.
Unused means not programatically refereced.
Proguard does NOT understand re ections.
Akka uses re ection much via Props or .conf le.
If Proguard is not con gured properly, then NoClassDefFoundError or
NoSuchMethodError are occured at runtime.
This is the most painful con guration to use Android Scala.
36. Do You Need to Con gure Proguard from Scratch?
No, absolutely.
provides a default setting for Scala standard library
jar.
This covers akka.actor and akka.io at least.
scala-android/sbt-android
proguard-con g.txt for akka-actor v2.3.16
39. It's Good Enough As a Starting Point.
As long as the library is smallish.
For example, you can add one liner to your proguard-con g.txt like:
-keep class akka.** { *; }
You'll want to revisit proguard-con g later on,
when your dex exceeds 64k methods.
MultiDex would also be an option.
when you release your app.
40. How to Con gure Proguard Properly.
Find and add classes which are used via re ection.
grep -r "classOf" . would be the easiest.
Check and add all classes which FQCN are listed in .conf le.
Add classes which occured NoClassDefFoundError or NoSuchMethodError at
runtime.
41. Proguard-Con g Will Look Like:
# Akka configuration
# Akka 2.3.16
## for akka.actor
### Classes used in reference.conf
#### akka.actor.provider
-keep class akka.actor.LocalActorRefProvider { *; }
#### akka.actor.guardian-supervisor-strategy
-keep class akka.actor.DefaultSupervisorStrategy { *; }
#### akka.actor.mailbox
-keep class akka.dispatch.UnboundedMailbox { *; }
-keep class akka.dispatch.BoundedMailbox { *; }
-keep class akka.dispatch.UnboundedDequeBasedMailbox { *; }
-keep class akka.dispatch.BoundedDequeBasedMailbox { *; }
#### akka.actor.mailbox.requirements
-keep class akka.dispatch.BoundedDequeBasedMessageQueueSemantics { *; }
-keep class akka.dispatch.UnboundedMessageQueueSemantics { *; }
-keep class akka.dispatch.UnboundedDequeBasedMessageQueueSemantics { *; }
-keep class akka.dispatch.DequeBasedMessageQueueSemantics { *; }
-keep class akka.dispatch.MultipleConsumerSemantics { *; }
#### akka.scheduler.implementation
-keep class akka.actor.LightArrayRevolverScheduler { *; }
42. Number of Methods and APK Size Comparison
In akka.actor and akka.io 2.3.16 (and Scala 2.11.11)
Proguard setting # of methods in
dex
APK
size
Keep-all-the-classes of Akka 35033 1132KB
15784 590KBKeep Akka classes only referenced by re ection
or conf
Disclaimer: This result is based on , and it may vary depending on how
many classes you use.
my sample
43. Will Android Support Java8?
Google has announced that Android current dex toolchain will support Java8.
Java 8 Language Features Support Update - Android Developers Blog
It's still uncertain if Android-Java8 support will work with Scala.
44. After Android Java8 Support Works
We might be able to enjoy:
Scala 2.12 or above
Smaller Scala standard lib jar.
Dotty(Scala 3.0) will introduce callgraph analysis from project,
that eliminates dead code. (no Proguard!)
Akka Streams (2.4 or above)
Great abstraction for ow graph, and handy back pressure management.
Akka Typed (2.5)
You can track Akka 2.5 release notes for exciting news about it.
Backo Supervisor (2.4 or above)
You can backport Backo Supervisor and ThreadLocalRandom for now.
Dotty-Linker
45. Memory Management
Android GC is Concurrent Mark & Sweep.
Watch out memory allocation & object creation.
WrappedArray#map or other higher functions box every primitive type
element.
works great.
Use ring bu ers for hotspots.
ByteString works well for concatenation or slicing.
Mutable objects within limited scope are your friend.
xuwei_k/nobox
46. Why not Kotlin?
🎉🎉🎉 for Android/Google o cial support!
Kotlin is great for Android, in terms of:
Smallish standard library jar.
Great IDE integration.
I still feel a big advantage in Scala lang functionality & ecosystem.
like Akka :)
47. Conclusion
Actor model works well in Android in stateful concurrent programming context.
Akka resiliency works great in error-prone situation, like an outdoor activities.
BONX Android app fully leverages Akka for its VoIP system.