Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AndroidでKotlinフル活用プログラミング #Kotlin_Sansan

AndroidでKotlinフル活用プログラミング #Kotlin_Sansan

AndroidでKotlin勉強会 @ Sansan で発表したスライドです。
http://connpass.com/event/22189/

Taro Nagasawa

January 15, 2016
Tweet

More Decks by Taro Nagasawa

Other Decks in Programming

Transcript

  1. AndroidでKotlin
    フル活用プログラミング
    2016-01-15
    AndroidでKotlin勉強会 @ Sansan
    長澤 太郎 @ngsw_taro

    View full-size slide

  2. 自己紹介
    ● 長澤 太郎 @ngsw_taro
    ● 仕事ではAndroidメイン、Java, Scala, Railsなど
    ● Kotlinエバンジェリスト(自称)
    ○ 講演や執筆などの実績多数
    ● 27歳、蟹座、ビール大好き

    View full-size slide

  3. 私のブログ

    View full-size slide

  4. アプリカティブなんとかみたいなやつ
    val minus = { a: Int -> { b: Int -> a - b } }
    fun T.bind(f: ((T)->R)?): R? = f?.invoke(this)
    y?.bind(x?.bind(minus))
    fun ((T)->R).apply(n: T?): R? = n?.bind(this)
    val sub: Int? = minus.apply(x)?.apply(y)
    http://taro.hatenablog.jp/entry/2014/04/06/144811

    View full-size slide

  5. メソッド参照みたいなやつ
    val (A.()->B).tof: (A)->B
    get() = { a: A -> a.this() }
    listOf("a", "bb", "ccc").map(String::length.tof)
    http://taro.hatenablog.jp/entry/2015/02/24/215413

    View full-size slide

  6. Extensionで
    なんでもするマン

    View full-size slide

  7. AndroidでKotlin
    Extensionプログラミング
    2016-01-15
    AndroidでKotlin勉強会 @ Sansan
    長澤 太郎 @ngsw_taro

    View full-size slide

  8. RxLifecycle面倒

    View full-size slide

  9. RxLifecycleを使う
    // in RxAppCompatActivity
    apiAccesss()
    .compose(bindToLifecycle())
    .subscribe {
    ...
    }
    省略できないっぽい

    View full-size slide

  10. こうしたい: 拡張関数使えばできそう
    // in RxAppCompatActivity
    apiAccesss()
    .bindToLifecycle()
    .subscribe {
    ...
    }

    View full-size slide

  11. こういうの作る
    // in RxAppCompatActivity
    fun Observable.bindToLifecycle() =
    compose(self.bindToLifecycle())
    いい感じ!
    共通部品化したい

    View full-size slide

  12. こういう提案
    interface RxLifecycleFeature: ActivityLifecycleProvider {
    fun Observable.bindToLifecycle() =
    compose([email protected]())
    }

    View full-size slide

  13. 使用側のアクティビティ
    class MyActivity: RxAppCompatActivity(),
    RxLifecycleFeature {
    fun go() {
    apiAccess()
    .bindToLifecycle()
    .subscribe {...}
    }
    }

    View full-size slide

  14. 明示的Activity起動の問題

    View full-size slide

  15. よくあるやつ: 遷移先
    class TargetActivity: Activity() {
    companion object {
    fun intent(c: Context, data: String) =
    Intent(c, TargetActivity::class.java)
    .putExtra(“data”, data)
    }
    }

    View full-size slide

  16. よくあるやつ: 遷移元
    class SourceActivity: Activity() {
    fun go() {
    val data = “hogefuga”
    startActivity(TargetActivity.intent(this, data))
    }
    }

    View full-size slide

  17. よくあるやつ: 遷移元
    class SourceActivity: Activity() {
    fun go() {
    val data = “hogefuga”
    startActivity(TargetActivity.intent(this, data))
    }
    } thisを書きたくない!
    簡単には拡張関数に
    できなさそう...

    View full-size slide

  18. Intent生成を遅らせる: 遷移先
    class TargetActivity: Activity() {
    companion object {
    fun intent(data: String) = { c: Context ->
    Intent(c, TargetActivity::class.java)
    .putExtra(“data”, data)
    }
    }
    }

    View full-size slide

  19. Intent生成を遅らせる: 遷移先
    class TargetActivity: Activity() {
    companion object {
    fun intent(data: String) = { c: Context ->
    Intent(c, TargetActivity::class.java)
    .putExtra(“data”, data)
    }
    }
    }
    Contextを取らなくなった

    View full-size slide

  20. Intent生成を遅らせる: 遷移先
    class TargetActivity: Activity() {
    companion object {
    fun intent(data: String) = { c: Context ->
    Intent(c, TargetActivity::class.java)
    .putExtra(“data”, data)
    }
    }
    }
    Context -> Intentな
    関数を返す

    View full-size slide

  21. イマイチな使用例: 遷移元
    class SourceActivity: Activity() {
    fun go() {
    val data = “hogefuga”
    startActivity(TargetActivity.intent(data)(this))
    }
    }

    View full-size slide

  22. よさげな使用例: 遷移元
    class SourceActivity: Activity() {
    fun go() {
    val data = “hogefuga”
    TargetActivity.intent(data).start()
    }
    fun ((Context)->Intent).start() {
    startActivity(this(applicationContext))
    }
    }

    View full-size slide

  23. よさげな使用例: 遷移元
    class SourceActivity: Activity() {
    fun go() {
    val data = “hogefuga”
    TargetActivity.intent(data).start()
    }
    fun ((Context)->Intent).start() {
    startActivity(this(applicationContext))
    }
    }
    ここからthisが消えた

    View full-size slide

  24. 共通部品化する for 遷移先
    inline fun
    intentBuilder(crossinline init: Intent.() -> Unit) =
    { context: Context ->
    Intent(context, T::class.java).apply {
    init()
    }
    }

    View full-size slide

  25. 共通部品を使う: 遷移先
    class TargetActivity: Activity() {
    companion object {
    fun intent(data: String) =
    intentBuilder {
    putExtra(“data”, data)
    }
    }
    }

    View full-size slide

  26. 共通部品化する for 遷移元
    interface IntentFeature {
    fun startActivity(intent: Intent)
    fun getApplicationContext()
    fun ((Context)->Intent).start() {
    startActivity(this(getApplicationContext()))
    }
    } インタフェースを継承するので
    はなく、抽象メソッドを定義して
    おく

    View full-size slide

  27. 共通部品を使う: 遷移元
    class SourceActivity: Activity(), IntentFeature {
    fun go() {
    val data = “hogefuga”
    TargetActivity.intent(data).start()
    }
    }

    View full-size slide

  28. おまけ: M11以前
    trait IntentFeature: Activity {
    fun ((Context)->Intent).start() {
    startActivity(this(getApplicationContext()))
    }
    }
    実装する側のクラスを
    指定できた

    View full-size slide

  29. Thank you,
    Enjoy Kotlin!

    View full-size slide