Your SlideShare is downloading. ×
  • Like
Android my Scala @ JFokus 2013
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Android my Scala @ JFokus 2013

  • 871 views
Published

A talk about Scala used to fight boilerplate while developing Android stuff. Presented at JFokus 2013

A talk about Scala used to fight boilerplate while developing Android stuff. Presented at JFokus 2013

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
871
On SlideShare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
14
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Scala Android Konrad Malawski / @ktosopl GeeCON / GDG / PJUG / KSUG / SCKRK JFokus 06.02.2013Wednesday, February 6, 13
  • 2. Konrad Malawski twitter: ktosoplWednesday, February 6, 13
  • 3. This will be...Wednesday, February 6, 13
  • 4. This will Not be...Wednesday, February 6, 13
  • 5. This will Not be...Wednesday, February 6, 13
  • 6. This will Not be... a Java rant, about app design.Wednesday, February 6, 13
  • 7. This will be about...Wednesday, February 6, 13
  • 8. This will be about...Wednesday, February 6, 13
  • 9. This will be about... shifting cognitive load writing less code fokus on goals, not meansWednesday, February 6, 13
  • 10. Scala isWednesday, February 6, 13
  • 11. Scala isWednesday, February 6, 13
  • 12. Scala is Simple , but Hard.Wednesday, February 6, 13
  • 13. Scala is Simple.Wednesday, February 6, 13
  • 14. Scala is Hard.object  Param  {    implicit  def  pToT[A[_],  B[_]](f:  (p:  Param[A])  =>  B[p.T]):  A~>B  =  new  (A  ~>  B)  {        def  apply[s](a:  A[s]):  B[s]  =  {            val  v:  Param[A]  {  type  T  =  s}  =  new  Param[A]  {                  type  T  =  s                def  in  =  a            }            f(v)        }    }} http://apocalisp.wordpress.com/2010/10/26/ type-level-programming -in-scala-part-7-natural-transformation%C2%A0literals/Wednesday, February 6, 13
  • 15. Scala is A Functional, Object Oriented, Statically Typed, Scalable, Language... ...running on the JVM and DVM!Wednesday, February 6, 13
  • 16. AndroidWednesday, February 6, 13
  • 17. findViewById public class MyActivity extends Activity { ListView comments; Button newComment; @Override void onCreate(Bundle bundle) { super.onCreate(bundle); comments = (ListView) findViewById(R.id.comments); newComment = (Button) findViewById(R.id.new_comment); // ... } }Wednesday, February 6, 13
  • 18. findViewById public class MyActivity extends Activity { ListView comments; is null at first... Button newComment; @Override void onCreate(Bundle bundle) { super.onCreate(bundle); comments = (ListView) findViewById(R.id.comments); newComment = (Button) findViewById(R.id.new_comment); // ... } }Wednesday, February 6, 13
  • 19. findViewById public class MyActivity extends Activity { ListView comments; Button newComment; initialized in @Override method... void onCreate(Bundle bundle) { super.onCreate(bundle); comments = (ListView) findViewById(R.id.comments); newComment = (Button) findViewById(R.id.new_comment); // ... } }Wednesday, February 6, 13
  • 20. findViewById public class MyActivity extends Activity { ListView comments; Button newComment; @Override void onCreate(Bundle bundle) { super.onCreate(bundle); comments = (ListView) findViewById(R.id.comments); newComment = (Button) findViewById(R.id.new_comment); // ... } } Explicit casting!Wednesday, February 6, 13
  • 21. Robo Guice So many public class MakeANoteActivity extends RoboActivity words... implements View.OnClickListener { public static final String PHOTO_PATH = "picture_path"; public static final String PHOTO_ATTACHED = "photo_attached"; @Inject SessionManager sessionManager; @Inject LocationHelper locationHelper; @Inject PhotoHelper photoHelper; @Inject Application context; @Inject CalibrationHelper calibrationHelper; @InjectView(R.id.attach_photo) Button attachPhoto; @InjectView(R.id.note_text) EditText noteText; @InjectView(R.id.save_button) Button save; @InjectView(R.id.date) TextView dateText; @InjectView(R.id.share) Button share; @InjectResource(R.string.im_aircasting) String imAircasting; @InjectResource(R.string.share_with) String shareWith; // ... }Wednesday, February 6, 13
  • 22. Robo Guice public class MakeANoteActivity extends RoboActivity implements View.OnClickListener { Guice is eager. public static final String PHOTO_PATH Startup can take a few seconds! = "picture_path"; public static final String PHOTO_ATTACHED = "photo_attached"; @Inject SessionManager sessionManager; @Inject LocationHelper locationHelper; @Inject PhotoHelper photoHelper; @Inject Application context; @Inject CalibrationHelper calibrationHelper; @InjectView(R.id.attach_photo) Button attachPhoto; @InjectView(R.id.note_text) EditText noteText; @InjectView(R.id.save_button) Button save; @InjectView(R.id.date) TextView dateText; @InjectView(R.id.share) Button share; @InjectResource(R.string.im_aircasting) String imAircasting; @InjectResource(R.string.share_with) String shareWith; // ... }Wednesday, February 6, 13
  • 23. Robo Guice public class MakeANoteActivity extends RoboActivity implements View.OnClickListener { public static final String PHOTO_PATH = "picture_path"; public static final String PHOTO_ATTACHED = "photo_attached"; @Inject SessionManager sessionManager; @Inject LocationHelper locationHelper; Type changes in XML, @Inject PhotoHelper photoHelper; but not here... @Inject Application context; ClassCastException! @Inject CalibrationHelper calibrationHelper; @InjectView(R.id.attach_photo) Button attachPhoto; @InjectView(R.id.note_text) EditText noteText; @InjectView(R.id.save_button) Button save; @InjectView(R.id.date) TextView dateText; @InjectView(R.id.share) Button share; @InjectResource(R.string.im_aircasting) String imAircasting; @InjectResource(R.string.share_with) String shareWith; // ... }Wednesday, February 6, 13
  • 24. Stairway to ScalaWednesday, February 6, 13
  • 25. Collections (the gateway drug)Wednesday, February 6, 13
  • 26. CollectionsWednesday, February 6, 13
  • 27. public class Person { private final String name; private final String nick; POJO public Person(String name, String nick) { this.name = name; this.nick = nick; } public String getName() { return name; } public String getNick() { return nick; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Person)) return false; Person person = (Person) o; if (name != null ? !name.equals(person.name) : person.name != null) return false; if (nick != null ? !nick.equals(person.nick) : person.nick != null) return false; return true; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (surname != null ? surname.hashCode() : 0); return result; } }Wednesday, February 6, 13
  • 28. public class Person { private final String name; private final String nick; POJO POSO* *Actually just a Case Class public Person(String name, String nick) { this.name = name; this.nick = nick; } public String getName() { return name; } public String getNick() { return nick; } @Override public boolean equals(Object o) { case class Person(name: String, nick: String) if (this == o) return true; if (!(o instanceof Person)) return false; Person person = (Person) o; if (name != null ? !name.equals(person.name) : person.name != null) return false; if (nick != null ? !nick.equals(person.nick) : person.nick != null) return false; return true; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (surname != null ? surname.hashCode() : 0); return result; } }Wednesday, February 6, 13
  • 29. POSO* *Actually just a Case Class val name: String case class Person(name: String, nick: String)Wednesday, February 6, 13
  • 30. Case Classes val person = Person("Bruce Wayne", "Manbat") // whoops! val fixed = person.copy(nick = "Batman") case class Person(name: String, nick: String) val self = Person(nick = "Ktoso" , name = "Konrad") val Person(name, hero) = person val hello = ”Hello” + name + ” ” + surname fixed.toString should equal (”Person(Bruce Wayne, Batman)”) Still thinking assertThat().isEqualTo() is clean?Wednesday, February 6, 13
  • 31. Scala Collections at Work Given a list of People, return all the Hero names. def heroNames(people: List[Person]): List[String] = people filter { _.isHero } map { _.name }Wednesday, February 6, 13
  • 32. Back to AndroidWednesday, February 6, 13
  • 33. Another look at the Java code public class MakeANoteActivity extends RoboActivity implements View.OnClickListener { public static final String PHOTO_PATH = "picture_path"; public static final String PHOTO_ATTACHED = "photo_attached"; @Inject SessionManager sessionManager; @Inject LocationHelper locationHelper; @Inject PhotoHelper photoHelper; @Inject Application context; @Inject CalibrationHelper calibrationHelper; @InjectView(R.id.attach_photo) Button attachPhoto; @InjectView(R.id.note_text) EditText noteText; @InjectView(R.id.save_button) Button save; @InjectView(R.id.date) TextView dateText; @InjectView(R.id.share) Button share; @InjectResource(R.string.im_aircasting) String imAircasting; @InjectResource(R.string.share_with) String shareWith; // ... }Wednesday, February 6, 13
  • 34. What if... Scala? class class MakeANoteActivity ScalaActivity publicMakeANoteActivity extendsextends RoboActivity with implements View.OnClickListener View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath public static final "picture_path" = String PHOTO_PATH = "picture_path"; val PhotoAttached = String PHOTO_ATTACHED = "photo_attached"; public static final "photo_attached" lazy val sessionManager = SessionManager.get @Inject SessionManager sessionManager; lazy val locationManager = LocationManager.get @Inject LocationHelper locationHelper; @Inject PhotoHelper photoHelper; @Inject Application context; @Inject CalibrationHelper calibrationHelper; lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText @InjectView(R.id.attach_photo) Button attachPhoto; = findView(TR.note_text) lazy val save @InjectView(R.id.note_text) EditText noteText; = findView(TR.save_button) lazy val dateText @InjectView(R.id.save_button) Button save; = findView(TR.date) lazy val share @InjectView(R.id.date) TextView dateText; = findView(TR.share) @InjectView(R.id.share) Button share; val username = findResource[String](R.string.my_username) @InjectResource(R.string.im_aircasting) String imAircasting; val friends = findResource[List[String]](R.string.friends) @InjectResource(R.string.share_with) String shareWith; def... // toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 35. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { public is default. = "picture_path" val PhotoPath val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 36. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" ScalaActivity gives us some val PhotoAttached = "photo_attached" magic methods lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 37. What if... Scala? class MakeANoteActivity extends ScalaActivity It’s so easy, with View.OnClickListener YOU can implement it! with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" ScalaActivity gives us some val PhotoAttached = "photo_attached" magic methods lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 38. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations Instead of “...Helper”, { use Traits. val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 39. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" Type Inference lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 40. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get Who’s missing here? lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 41. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get lazy initialization lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 42. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get Needs Context lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) Implicit Parameters lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 43. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get What’s the type here?!? lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 44. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get What’s the type here?!? Typed Resource - “a better R” lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 45. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get What’s the type here?!? Typed Resource - “a better R” lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) XML Type changes... Type here changes! val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 46. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get What’s the type here?!? Typed Resource - “a better R” lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share: Button = findView(TR.share) You can be explicit though! val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 47. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = Like @InjectResource, but findView(TR.share) smarter val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() } Manifests vs. Type ErasureWednesday, February 6, 13
  • 48. What if... Scala? class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) Does String have a toast() val username = findResource[String](R.string.my_username) method? val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() } Implicit ConversionWednesday, February 6, 13
  • 49. Typed ResourceWednesday, February 6, 13
  • 50. Typed Resource = Better RWednesday, February 6, 13
  • 51. class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get lazy val locationManager = LocationManager.get Typed Resource = Better R lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) Typed Resource val username = findResource[String](R.string.my_username) val friends = findResource[List[String]](R.string.friends) def toastConferenceName() = "KrakDroid".toast() }Wednesday, February 6, 13
  • 52. Typed Resource = Better R <TableLayout  android:id="@+id/login_table"                                  android:layout_gravity="center"                                  android:layout_height="wrap_content"                                  android:layout_width="wrap_content"> case class TypedResource[T](id: Int) case class TypedLayout(id: Int) Wrappers object TR { val login_table = TypedResource[TableLayout](R.id.login_table) val workspaces = TypedResource[ExpandableListView](R.id.workspaces) val subtask_txt = TypedResource[TextView](R.id.subtask_txt) // ... }Wednesday, February 6, 13
  • 53. Typed Resource = Better R <TableLayout  android:id="@+id/login_table"                                  android:layout_gravity="center"                                  android:layout_height="wrap_content"                                  android:layout_width="wrap_content"> case class TypedResource[T](id: Int) case class TypedLayout(id: Int) object TR { val login_table = TypedResource[TableLayout](R.id.login_table) val workspaces = TypedResource[ExpandableListView](R.id.workspaces) val subtask_txt = TypedResource[TextView](R.id.subtask_txt) // ... }Wednesday, February 6, 13
  • 54. TR in Action class MakeANoteActivity extends ScalaActivity with View.OnClickListener with PhotoOperations with CalibrationOperations { val PhotoPath = "picture_path" val PhotoAttached = "photo_attached" lazy val sessionManager = SessionManager.get // magic here but lazy val locationManager = LocationManager.get // we’ll see this later! lazy val attachPhoto = findView(TR.attach_photo) lazy val noteText = findView(TR.note_text) lazy val save = findView(TR.save_button) lazy val dateText = findView(TR.date) lazy val share = findView(TR.share) // magic here too, but we’ll implement this in a few slides! val imAircasting = findResource[String](R.string.im_aircasting) val shareWith = findResource[String](R.string.share_with) // ... }Wednesday, February 6, 13
  • 55. Types You always have the type information at hand. (IntelliJ IDEA, ENSIME/Emacs, Eclipse) ⌘ SHIFT I ALT =Wednesday, February 6, 13
  • 56. MenusWednesday, February 6, 13
  • 57. Menus = callbacksWednesday, February 6, 13
  • 58. Java @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); return true; } Menus = callbacksWednesday, February 6, 13
  • 59. Menus = callbacks Java @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.new_game: newGame(); return true; case R.id.help: showHelp(); return true; default: return super.onOptionsItemSelected(item); } }Wednesday, February 6, 13
  • 60. Menus = callbacks Java public class AnActivity extends Activity { public class AnActivity extends Activity { } }Wednesday, February 6, 13
  • 61. Menus = callbacks Java public class AnActivity extends Activity { th is? to fix ways tyle } Ja v a-s public class AnActivity extends Activity { }Wednesday, February 6, 13
  • 62. Delegate! Delegate! Delegate! Java public class GameMenu { public boolean onCreateOptionsMenu(Menu menu) { /*...*/ } public boolean onOptionsItemSelected(MenuItem item) { /*...*/ } } public class AnActivity extends Activity { GameMenu gameMenu = ... public boolean onCreateOptionsMenu(Menu menu) { return gameMenu.onCreateOptionsMenu(menu); } public boolean onOptionsItemSelected(MenuItem item) { return gameMenu.onOptionsItemSelected(item) } }Wednesday, February 6, 13
  • 63. super class monster Java public abstract class WithGameMenuActivity extends Activity { public boolean onCreateOptionsMenu(Menu menu) { /*...*/ } public boolean onOptionsItemSelected(MenuItem item) { /*...*/ } } public class AnActivity extends WithGameMenuActivity { }Wednesday, February 6, 13
  • 64. Menus = callbacks Java public class AnActivity extends Activity { th is? to fix ays -styl ew cala public class AnActivity extends Activity { } S }Wednesday, February 6, 13
  • 65. Converting is simple @Override public boolean onCreateOptionsMenu(Menu menu) { override def onCreateOptionsMenu(Menu menu) = MenuInflater inflater = getMenuInflater(); val inflater = getMenuInflater() inflater.inflate(R.menu.game_menu, menu); menu) return true; true } @Override override def onOptionsItemSelected(MenuItem item) = public boolean onOptionsItemSelected(MenuItem item) { item.getItemId() match { switch (item.getItemId()) { casecase R.id.new_game: R.id.new_game => newGame(); true case R.id.help newGame(); => showHelp(); true case _ return true; super.onOptionsItemSelected(item) => } case R.id.help: showHelp(); return true; default: return super.onOptionsItemSelected(item); } }Wednesday, February 6, 13
  • 66. The Menu Trait Scala trait GameMenu { override def onCreateOptionsMenu(Menu menu) = { val inflater = getMenuInflater() inflater.inflate(R.menu.game_menu, menu) true } Uhm... but were not an Activity here! override def onOptionsItemSelected(MenuItem item) = item.getItemId() match { case R.id.new_game => newGame(); true case R.id.help => showHelp(); true case _ => super.onOptionsItemSelected(item) } }Wednesday, February 6, 13
  • 67. The Menu Trait Scala trait GameMenu { Now were sure "Im in an Activity" this: Activity => override def onCreateOptionsMenu(Menu menu) = { val inflater = getMenuInflater() inflater.inflate(R.menu.game_menu, menu) true } override def onOptionsItemSelected(MenuItem item) = item.getItemId() match { case R.id.new_game => newGame(); true case R.id.help => showHelp(); true case _ => super.onOptionsItemSelected(item) } }Wednesday, February 6, 13
  • 68. The Menu Traits class MyGame extends Activity with GameMenu with SomeContextMenuWednesday, February 6, 13
  • 69. An Implicit ContextWednesday, February 6, 13
  • 70. Passing around Context Toast.makeText(ctx, msg, LENGTH_LONG).show(); Intent intent = new Intent(context, LocalService.class);Wednesday, February 6, 13
  • 71. An Implicit Context def toastMyName(name: String, ctx: Context) { import android.widget.Toast._ Implicit != Explicit makeText(ctx, msg, LENGTH_LONG).show() } toastMyName(”Siegfried”, getContext)Wednesday, February 6, 13
  • 72. An Implicit Context Implicit != Explicit def toastMyName(name: String, ctx: Context) { import android.widget.Toast._ makeText(ctx, msg, LENGTH_LONG).show() } Explicit Parameter toastMyName(”Siegfried”, getContext)Wednesday, February 6, 13
  • 73. An Implicit Context Implicit != Explicit def toastMyName(name: String, ctx: Context) { import android.widget.Toast._ makeText(ctx, msg, LENGTH_LONG).show() } Explicit Parameter toastMyName(”Siegfried”, getContext)Wednesday, February 6, 13
  • 74. An Implicit Context Implicit != Explicit Import inside a method! def toastMyName(name: String, ctx: Context) { import android.widget.Toast._ makeText(ctx, msg, LENGTH_LONG).show() } toastMyName(”Siegfried”, getContext)Wednesday, February 6, 13
  • 75. An Implicit Context Implicit != Explicit def toastMyName(name: String)(implicit ctx: Context) {{ def toastMyName(name: String, ctx: Context) import android.widget.Toast._ import android.widget.Toast._ makeText(ctx, msg, LENGTH_LONG).show() makeText(ctx, msg, LENGTH_LONG).show() } } toastMyName(”Siegfried”, getContext)Wednesday, February 6, 13
  • 76. Implicit Parameters Implicit != Explicit def toastMyName(name: String)(implicit ctx: Context) { import android.widget.Toast._ makeText(ctx, msg, LENGTH_LONG).show() Implicit Parameter }Wednesday, February 6, 13
  • 77. Implicit Parameters Implicit != Explicit def toastMyName(name: String)(implicit ctx: Context) { import android.widget.Toast._ makeText(ctx, msg, LENGTH_LONG).show() } implicit val context: Context = getContext toastMyName("Siegfried") toastMyName("Siegfried")(context)Wednesday, February 6, 13
  • 78. An Implicit Context class ScalaActivity extends Activity with ImplicitContext “I can be only mixed into an Activity.” trait ImplicitContext { this: Activity => implicit val ctx = getContext } So I know this method!Wednesday, February 6, 13
  • 79. Implicit ConversionsWednesday, February 6, 13
  • 80. Implicit Conversions Implicit != ExplicitWednesday, February 6, 13
  • 81. Implicit Conversions Implicit != Explicit Implicit Context, remember? toastMyName("Siegfried") What if we could... "Siegfried".toast()Wednesday, February 6, 13
  • 82. Implicit Conversions Implicit != Explicit Decorator Constructor class Toastable(msg: String) { def toast()(implicit ctx: Context) = ??? } new Toastable("Hello!").toast()Wednesday, February 6, 13
  • 83. Implicit Conversions Implicit != Explicit class Toastable(msg: String) { def toast()(implicit ctx: Context) = ??? } Implicit Conversion: String => Toastable trait ScalaToasts { implicit def asToastable(str: String) = new Toastable(str) } asToastable("Hello!").toast()Wednesday, February 6, 13
  • 84. Implicit Conversions Implicit != Explicit class Toastable(msg: String) { def toast()(implicit ctx: Context) = ??? } Implicit Conversion: String => Toastable trait ScalaToasts { implicit def asToastable(str: String) = new Toastable(str) } "Hello!".toast() class ExampleActivity extends Activity with ImplicitContext with ScalaToastsWednesday, February 6, 13
  • 85. Implicit Conversions Implicit != Explicit class Toastable(msg: String) { def toast()(implicit ctx: Context) = ??? } trait ScalaToasts { implicit def asToastable(str: String) = new Toastable(str) } "Hello!".toast() class ExampleActivity extends Activity asToastable("Hello!").toast() with ImplicitContext with ScalaToastsWednesday, February 6, 13
  • 86. Implicit ConversionsWednesday, February 6, 13
  • 87. And there’s more!Wednesday, February 6, 13
  • 88. Simple Threading implicit val handler = new Handler inUiThread { // ... } inFutureWithProgressDialog(timeout = 10.seconds) { // ... } Implicit Conversion on Int Not a replacement for proper designWednesday, February 6, 13
  • 89. on___ button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // ... } }); button onClick { view => // ... }Wednesday, February 6, 13
  • 90. SharedPreferences KanbaneryPreferences.projectId = 1337 val name: Option[Long] = KanbaneryPreferences.projectIdWednesday, February 6, 13
  • 91. SharedPreferences object KanbaneryPreferences { private val KeyLogin = "login" private def sharedPreferences(implicit ctx: Context) = ??? def login(implicit ctx: Context) = sharedPreferences.getString(KeyLogin, "")Wednesday, February 6, 13
  • 92. SharedPreferences object KanbaneryPreferences { private val KeyLogin = "login" private def sharedPreferences(implicit ctx: Context) = ??? def login_=(number: String)(implicit ctx: Context) { withSharedPreferencesEditor { _.putString(KeyLogin, number) } }Wednesday, February 6, 13
  • 93. SharedPreferences object KanbaneryPreferences { private val KeyLogin = "login" private def sharedPreferences(implicit ctx: Context) = ??? def login_=(number: String)(implicit ctx: Context) { withSharedPreferencesEditor { _.putString(KeyLogin, number) } }Wednesday, February 6, 13
  • 94. SharedPreferences def withSharedPreferencesEditor (block: SharedPreferences.Editor => Unit) (implicit ctx: Context) { val editor = sharedPreferences.edit() block(editor) editor.commit() } withSharedPreferencesEditor { _.putString(KeyLogin, number) }Wednesday, February 6, 13
  • 95. Let me warn you... Scala is addictive.Wednesday, February 6, 13
  • 96. Let me warn you... Scala is addictive.Wednesday, February 6, 13
  • 97. Scala is addictive.Wednesday, February 6, 13
  • 98. Scala my Android?Wednesday, February 6, 13
  • 99. Scala my Android?Wednesday, February 6, 13
  • 100. Scala my Android? - Android Library projects? - Not "Java level" IDE support? - Debugging? - ProGuard-ing time? - Increased cognitive load?Wednesday, February 6, 13
  • 101. Scala my Android? + No boilerplate + Focus on the app/domain + No need for reflection + Less cognitive load? + Scala libraries + SBT (build tool)Wednesday, February 6, 13
  • 102. def links = • Scala Lang http://www.scala-lang.org/ • Scala Koans http://www.scalakoans.org • Blog.Project13.pl - http://www.blog.project13.pl • SBT Android Plugin - https://github.com/jberkel/android-plugin • Kanbanery for Android - https://github.com/ktoso/kanbanery-tv • Check pl.project13.scala.android.* • Fully Open Source • New version soon! Pull and play with it! • Scaloid https://github.com/pocorall/scaloid • Many of the things weve seen, a bit more; some awesome, some less Mailing lists rock!Wednesday, February 6, 13
  • 103. I love feedback! <3 Konrad Malawski / @ktosopl GeeCON / GDG / PJUG / KSUG / SCKRK JFokus 06.02.2013Wednesday, February 6, 13