On Github ktoso / scala-android-presentation
?
means Stairs
val conference = "Mobilizejszon" // conference = "mobilization" // compile error val == "java final" var age = 90 age = 2 // age = "trolololo!" // compile error String != Int
val name: String = "Mobilization"
val name: String = "Mobilization" ; // yay semicolons, GREAT!!!
public class Person { private String name; private String surname; public Person(String name, String surname) { this.name = name; this.surname = surname; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } @Override public String toString() { /*...*/ } }
class Person(name: String, surname: String)"You forgot the toString()!"
case class Person(name: String, age: Int)
List<String> girls = FluentIterable .from(people) .filter(new Predicate<Person>() { @Override public boolean apply(Person person) { return person != null && person.isWoman(); } }) .transform(new Function<Person, String>() { @Override public String apply(Person input) { return input.getFirstName() + " " + input.getLastName(); } }) .toImmutableList(); for(String name : names) println(String.format("Hello %s!", name); // PS: DON'T call format on Android!
people.filter(_.isWoman)
people.filter(_.isWoman).map(_.name)
people.filter(_.isWoman).map(_.name).foreach(greet _)
def greet(name: String) = println("Hello " + name + "!") people filter { _.isWoman } map { _.name } foreach { n => greet _ }
people foreach println
val bothSets: Set[String] = set ++ anotherSetand others...
<Button android:id="@+id/my_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/my_button_text">
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); } }What sucks here? Tip: One thing is fixable by RoboGuice.
class MyScalaActivity extends ScalaActivity { lazy val Comments = findView(TR.comments) lazy val NewComment = findView(TR.new_comment) // with Types! }
var thing = 0 lazy val incrementInLazyVal = { thing += 1; thing } thing = 100 incrementInLazyVal incrementInLazyVal incrementInLazyVal assert { thing == 101 && incrementInLazyVal == 101 }
var thing = 0 val incrementInVal = { thing += 1; thing } thing = 100 incrementInVal incrementInVal incrementInVal assert { thing == 1 && incrementInVal == 1 }
var thing = 0 def incrementDef() = { thing += 1; thing } incrementDef() incrementDef incrementDef assert { thing == 3 }
def something = 1337 something // OK something() // compile errorIntuition is: "() means side-effects"
trait SayVerb { // some magic here... Comes after the next few slides ;-) def sayAwesome() = "Awesome!".toast() // make a toast! def sayAmazing() = "Amazing!".toast() } trait Logging { /* logging impl */ }
class MyActivity extends Activity with SayVerb with Logging
public class ActivityA extends Activity { @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); return true; } }
public class ActivityB extends Activity { @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); return true; } }
trait GameMenu extends Activity { override onCreateOptionsMenu(menu: Menu) = { getMenuInflater.inflate(R.menu.game_menu, menu) true } }
class ActivityA extends Activity with GameMenu { /*...*/ } class ActivityB extends SomethingFromAFrameworkActivity with GameMenu { /*...*/ }
trait ContentView extends Activity with TypedActivity { // force the user to implement this "method? / field?" def ContentView: TypedLayout override def onCreate(bundle: Bundle) { setContentView(ContentView.id) super.onCreate(bundle) } }
class LoginActivity extends ScalaActivity with ViewListenerConversions with ContentView { // we implement the def ContentView with a value! val ContentView = TR.layout.login }
object Dictionary extends Logging with TimedVerb with RetryVerb with DoToVerb with UniquifyVerb
def things() { import Dictionary._ // use this dictionaty }(imagine _ works like * in Java).
"Hello world!".toastSo... where did that method come from? That IS a java.lang.String right? ...right?
// Scala "magic" here val it: java.lang.String = "Hello %s!" it.format("Łódź") == "Hello Łódź!"
implicit def string2richString(s: String) = new RichString(s) // String -> RichString
"%s".format("aha!") // compiler starts looking... // and REWRITES it to: new RichString("%s").format("aha!")
Back to our Toast example
Java:
Toast.makeText(ctx, msg, Toast.LENGTH_SHORT).show()Problems?
def add(a: Int): (Int) => Int = addStep2(a, _) // add returns a function that takes an Int, and returns an Int def addStep2(a: Int, b: Int) = a + b // the final step, adding those numbers // usage: val part2 = add(2)(2)We're able to write:
def add(a: Int)(b: Int) = a + bTremendously useful!
// IMPLICIT VALUE implicit val ctx = getApplicationContext() // IMPLICIT PARAMETER LIST def example()(implicit ctx: Context) = "I have " + ctx
example()(getApplicationContext) // or! implicit val ctx = getApplicationContext example()
trait Toasts { implicit def charSeq2toastable(str: java.lang.CharSequence) = new Toastable(str.toString) class Toastable(msg: String) { import android.widget.Toast._ def toast(implicit ctx: Context) { makeText(ctx, msg, LENGTH_LONG).show() } } }Usage:
class MyActivity extends Activity with Toasts { implicit lazy val ctx = getApplicationContext def sayHello() { "Hello".toast } }
SomeTextView.setText("Hello World!")
SomeTextView := "Hello World!"
SomeTextView.:=("Hello World!")
button.setOnClickListener(new OnClickListener() { public void onClick(View v) { // do things... } });
import ListenerConversions._ button onClick { /* do things */ }
// even better: val sendMessage = { /*...*/ } button onClick sendMessage
handler.post(new Runnable(){ @Override void run() { /* ... */ } });
inFuture { /* ... */ } inUiThread { /*...*/ } inFuture(whenComplete = notifyUser) { /* long task...*/ } inFutureWithProgressDialog { /* long task...*/ }
SharedPreferences sp = ctx.getSharedPreferences(key, 0); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("key", "value"); editor.commit();
AppSharedPreferences.someKey = "value"No implicit's here!
def sharedPreferences(implicit ctx: Context) = ctx.getSharedPreferences(AppName, 0)
def workspaceName(implicit ctx: Context) = Option { sharedPreferences.getString(KeyWorkspaceName, null) }
def workspaceName_=(name: String)(implicit ctx: Context) { withSharedPreferencesEditor { _.putString(KeyWorkspaceName, name) } }Notice the method name: "something_="
optionalValue map { _.toast }Which will only be called, if the Option has Some value.
Intent intent = new Intent(this, A.class); intent.putExtra("user_id", 1234); intent.putExtra("data", new SomeData()); startActivity(intent);
public class A extends Activity { @Override public void onCreate(Bundle savedInstance) { super.onCreate(savedInstance); int userId = getIntent().getIntExtra("user_id"); SomeData data = (SomeData) getIntent().getSerializableExtra("data"); }
Intents.Login.show()Read:
public class A extends Activity { @Override public void onCreate(Bundle savedInstance) { super.onCreate(savedInstance); LoginData data = Intents.Login.getData(getIntent()); }
interface Intents { abstract class Login { /*...*/ } abstract class Messages { /*...*/ } // etc... }
if("Bob".equals(person.getName()) { String name = person.getName(); String surname = person.getSurname(); // do things... } else { Log.d("You're not Bob!"); }
person match { case Person("Bob", surname) => ("Bob's surname is: " + surname).toast case _ => "You're not Bob!".toast }
class Data(num: Int)
object Data { // that's called an "companion object" def apply(num: Int) = new Data(num) def unapply(i: Intent): Option[Data] = if (i.hasExtra("num")) Some(new Data(i.getIntExtra("num"))) else None }
val data = Data(1) // is the same as: val data2 = Data.apply(2)Remember Some(12)? Same thing.
data match { case Data(num) => assert { num == 1 } // matches here! num = 1 case _ => ??? }
data match { case Data(333) => ??? case Data(1) => // matches here! }
data match { case Something(a, b) => case other => // matches here }
> ~test