ObservableArrayとPikkel

 ObservableArrayとPikkel

第3回 Kotlin勉強会 in Sansan
#Kotlin_Sansan

C057726b79d9eaed10c136794ef833fa?s=128

Jumpei Yamamoto

July 01, 2016
Tweet

Transcript

  1. Copyright © Sansan, Inc. All rights reserved. > ObservableArray >

    Pikkel Jumpei Yamamoto 2016.7.1 第3回 Kotlin勉強会 in Sansan #kotlin_sansan
  2. Copyright © Sansan, Inc. All rights reserved. > ⾃⼰紹介 -

    ⼭本純平 - Sansan株式会社 Eight事業部 - EightのAndroidアプリの開発 - twitter: @boohbah - github: https://github.com/yamamotoj
  3. Copyright © Sansan, Inc. All rights reserved. 3

  4. Copyright © Sansan, Inc. All rights reserved. 4

  5. Copyright © Sansan, Inc. All rights reserved. > Eightの新機能「オンライン名刺交換」 -

    もう紙の名刺はいらない! - NearByで周囲のEightユー ザーを検索 - 複数のユーザー間でも名刺 交換ができる
  6. Copyright © Sansan, Inc. All rights reserved. > アジェンダ -

    ⾃作のライブラリを2つ紹介 - ObservableArray - Pikkel
  7. Copyright © Sansan, Inc. All rights reserved. > ObservableArrayとは -

    変更の通知を受け取れるArray Interface
  8. Copyright © Sansan, Inc. All rights reserved. > ObservableArray interface

    ObservableArray<T> { val size: Int operator fun get(index: Int): T fun updates(): Observable<Event> sealed class Event { class DataSetChanged : Event() class ItemChanged(val position: Int) : Event() class ItemInserted(val position: Int) : Event() class ItemRemoved(val position: Int) : Event() } }
  9. Copyright © Sansan, Inc. All rights reserved. > ObservableArray interface

    ObservableArray<T> { val size: Int operator fun get(index: Int): T fun updates(): Observable<Event> sealed class Event { class DataSetChanged : Event() class ItemChanged(val position: Int) : Event() class ItemInserted(val position: Int) : Event() class ItemRemoved(val position: Int) : Event() } }
  10. Copyright © Sansan, Inc. All rights reserved. > ObservableArray interface

    ObservableArray<T> { val size: Int operator fun get(index: Int): T fun updates(): Observable<Event> sealed class Event { class DataSetChanged : Event() class ItemChanged(val position: Int) : Event() class ItemInserted(val position: Int) : Event() class ItemRemoved(val position: Int) : Event() } } operator overloadで array[0] という形のアクセスが可能
  11. Copyright © Sansan, Inc. All rights reserved. > ObservableArray interface

    ObservableArray<T> { val size: Int operator fun get(index: Int): T fun updates(): Observable<Event> sealed class Event { class DataSetChanged : Event() class ItemChanged(val position: Int) : Event() class ItemInserted(val position: Int) : Event() class ItemRemoved(val position: Int) : Event() } } 変更の通知を受け取ることが可能
  12. Copyright © Sansan, Inc. All rights reserved. > ObservableArray interface

    ObservableArray<T> { val size: Int operator fun get(index: Int): T fun updates(): Observable<Event> sealed class Event { class DataSetChanged : Event() class ItemChanged(val position: Int) : Event() class ItemInserted(val position: Int) : Event() class ItemRemoved(val position: Int) : Event() } } sealed classで複数のEventを定義
  13. Copyright © Sansan, Inc. All rights reserved. RecyclerViewの Adapterで使われることを想定 0CTFSWBCMF"SSBZ

    変更の通知
  14. Copyright © Sansan, Inc. All rights reserved. > ArrayListを使った実装 class

    ObservableArrayList<T>( private val arrayList: ArrayList<T> ) : ObservableArray<T> { private val updateSubject = PublishSubject.create<Event>() override val size: Int get() = arrayList.size override fun get(index: Int): T = arrayList[index] override fun updates() = updateSubject fun add(index: Int, elem: T) { arrayList.add(index, elem) updateSubject.onNext(Event.ItemInserted(index)) }
  15. Copyright © Sansan, Inc. All rights reserved. > ArrayListを使った実装 class

    ObservableArrayList<T>( private val arrayList: ArrayList<T> ) : ObservableArray<T> { private val updateSubject = PublishSubject.create<Event>() override val size: Int get() = arrayList.size override fun get(index: Int): T = arrayList[index] override fun updates() = updateSubject fun add(index: Int, elem: T) { arrayList.add(index, elem) updateSubject.onNext(Event.ItemInserted(index)) } VQEBUFT ͸ 1VCMJTI4VCKFDUͰ࣮૷
  16. Copyright © Sansan, Inc. All rights reserved. > ArrayListを使った実装 class

    ObservableArrayList<T>( private val arrayList: ArrayList<T> ) : ObservableArray<T> { private val updateSubject = PublishSubject.create<Event>() override val size: Int get() = arrayList.size override fun get(index: Int): T = arrayList[index] override fun updates() = updateSubject fun add(index: Int, elem: T) { arrayList.add(index, elem) updateSubject.onNext(Event.ItemInserted(index)) } ཁૉͷ௥Ճ࣌ʹ*UFN*OTFSUFEΠϕϯτΛ ౤͛Δ
  17. Copyright © Sansan, Inc. All rights reserved. ArrayListでの実装 0CTFSWBCMF"SSBZ ArrayList

  18. Copyright © Sansan, Inc. All rights reserved. Realmでの実装 0CTFSWBCMF"SSBZ Realm

  19. Copyright © Sansan, Inc. All rights reserved. > operatorを拡張関数で追加 operator

    fun <T> ObservableArray<T>.plus(other: ObservableArray<T>) : ObservableArray<T>{ /* .... */ }
  20. Copyright © Sansan, Inc. All rights reserved. > operatorを拡張関数で追加 operator

    fun <T> ObservableArray<T>.plus(other: ObservableArray<T>) : ObservableArray<T>{ /* .... */ } // plusϝιουͰ + ԋࢉࢠͷ࣮૷Λஔ͖׵͑Δ val array1: ObservableArray<String>() val array2: ObservableArray<String>() val array3 = array1 + array2 // ࿈݁
  21. Copyright © Sansan, Inc. All rights reserved. > operator fun

    plus()の実装 operator fun <T> ObservableArray<T>.plus(other: ObservableArray<T>) : ObservableArray<T> = object : ObservableArray<T> { override val size: Int get() = this@plus.size + other.size override fun get(index: Int): T = if (index < this@plus.size) { this@plus[index] } else { other[index - this@plus.size] } override fun updates(): Observable<Event> { ... } }
  22. Copyright © Sansan, Inc. All rights reserved. > operator fun

    plus()の実装 operator fun <T> ObservableArray<T>.plus(other: ObservableArray<T>) : ObservableArray<T> = object : ObservableArray<T> { override val size: Int get() = this@plus.size + other.size override fun get(index: Int): T = if (index < this@plus.size) { this@plus[index] } else { other[index - this@plus.size] } override fun updates(): Observable<Event> { ... } } ৽͍͠ແ໊ΫϥεΛੜ੒
  23. Copyright © Sansan, Inc. All rights reserved. > operator fun

    plus()の実装 operator fun <T> ObservableArray<T>.plus(other: ObservableArray<T>) : ObservableArray<T> = object : ObservableArray<T> { override val size: Int get() = this@plus.size + other.size override fun get(index: Int): T = if (index < this@plus.size) { this@plus[index] } else { other[index - this@plus.size] } override fun updates(): Observable<Event> { ... } } 2ͭͷarrayͷsizeΛ଍͢
  24. Copyright © Sansan, Inc. All rights reserved. > operator fun

    plus()の実装 operator fun <T> ObservableArray<T>.plus(other: ObservableArray<T>) : ObservableArray<T> = object : ObservableArray<T> { override val size: Int get() = this@plus.size + other.size override fun get(index: Int): T = if (index < this@plus.size) { this@plus[index] } else { other[index - this@plus.size] } override fun updates(): Observable<Event> { ... } } 2ͭͷarray͔ΒelementͷऔಘઌΛ ৼΓ෼͚Δ
  25. Copyright © Sansan, Inc. All rights reserved. > operator fun

    plus()の実装 operator fun <T> ObservableArray<T>.plus(other: ObservableArray<T>) : ObservableArray<T> = object : ObservableArray<T> { override val size: Int get() = this@plus.size + other.size override fun get(index: Int): T { … } override fun updates(): Observable<Event> = Observable.merge( this@plus.updates(), other.updates().map { val offset = this@plus.size when (it) { is Event.DataSetChanged -> it is Event.ItemChanged -> Event.ItemChanged(it.position + offset) is Event.ItemInserted -> Event.ItemInserted(it.position + offset) is Event.ItemRemoved -> Event.ItemRemoved(it.position + offset) } } ) }
  26. Copyright © Sansan, Inc. All rights reserved. > operator fun

    plus()の実装 operator fun <T> ObservableArray<T>.plus(other: ObservableArray<T>) : ObservableArray<T> = object : ObservableArray<T> { override val size: Int get() = this@plus.size + other.size override fun get(index: Int): T { … } override fun updates(): Observable<Event> = Observable.merge( this@plus.updates(), other.updates().map { val offset = this@plus.size when (it) { is Event.DataSetChanged -> it is Event.ItemChanged -> Event.ItemChanged(it.position + offset) is Event.ItemInserted -> Event.ItemInserted(it.position + offset) is Event.ItemRemoved -> Event.ItemRemoved(it.position + offset) } } ) } 2ͭͷarray͔Βͷupdates()Λ merge
  27. Copyright © Sansan, Inc. All rights reserved. > operator fun

    plus()の実装 operator fun <T> ObservableArray<T>.plus(other: ObservableArray<T>) : ObservableArray<T> = object : ObservableArray<T> { override val size: Int get() = this@plus.size + other.size override fun get(index: Int): T { … } override fun updates(): Observable<Event> = Observable.merge( this@plus.updates(), other.updates().map { val offset = this@plus.size when (it) { is Event.DataSetChanged -> it is Event.ItemChanged -> Event.ItemChanged(it.position + offset) is Event.ItemInserted -> Event.ItemInserted(it.position + offset) is Event.ItemRemoved -> Event.ItemRemoved(it.position + offset) } } ) } ޙΖͷarray͔ΒͷupdateͰ͸ indexΛͣΒ͢
  28. Copyright © Sansan, Inc. All rights reserved. > ObservableArray interface

    ObservableArray<T> { val size: Int operator fun get(index: Int): T fun updates(): Observable<Event> sealed class Event { class DataSetChanged : Event() class ItemChanged(val position: Int) : Event() class ItemInserted(val position: Int) : Event() class ItemRemoved(val position: Int) : Event() } }
  29. Copyright © Sansan, Inc. All rights reserved. 29 +

  30. Copyright © Sansan, Inc. All rights reserved. > Eightでの使っているところ 30

    ユーザー通知⽤ Item オンメモリ 投稿⽤ Item (固定) フィード表⽰⽤ Item Realm それぞれをObservableArrayとして それを合成
  31. Copyright © Sansan, Inc. All rights reserved. > 公開してます -

    本体の実装は50⾏! - https://github.com/yamamotoj/ObservableArray
  32. > Pikkel

  33. Copyright © Sansan, Inc. All rights reserved. > IcePick class

    ExampleActivity extends Activity { @State String username; // This will be automatically saved and restored @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Icepick.restoreInstanceState(this, savedInstanceState); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this, outState); } // You can put the calls to Icepick into a BaseActivity // All Activities extending BaseActivity automatically have state saved/restored } ͜ΕΛKotlinͷػೳΛ͔࣮ͭͬͯ૷ͯ͠Έͨ
  34. Copyright © Sansan, Inc. All rights reserved. > Pikkel class

    MainActivity : Activity(), Pikkel by PikkelDelegate() { var data by state<String?>(null) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) restoreInstanceState(savedInstanceState) } override fun onSaveInstanceState(outState: Bundle?) { super.onSaveInstanceState(outState) saveInstanceState(outState) } } ͓·͡ͳ͍
  35. Copyright © Sansan, Inc. All rights reserved. class MainActivity :

    Activity(), Pikkel by PikkelDelegate() { var data by state<String?>(null) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) restoreInstanceState(savedInstanceState) } override fun onSaveInstanceState(outState: Bundle?) { super.onSaveInstanceState(outState) saveInstanceState(outState) } } อଘ͍ͨ͠ϓϩύςΟΛ by state<T>() ͷ delegated propertyͰࢦఆ
  36. Copyright © Sansan, Inc. All rights reserved. class MainActivity :

    Activity(), Pikkel by PikkelDelegate() { var data by state<String?>(null) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) restoreInstanceState(savedInstanceState) } override fun onSaveInstanceState(outState: Bundle?) { super.onSaveInstanceState(outState) saveInstanceState(outState) } } onSaveInstanceState() Ͱstate()ࢦఆ͍ͯͨ͠ϓϩύ ςΟ͕ࣗಈతʹอଘ͞ΕΔ
  37. Copyright © Sansan, Inc. All rights reserved. class MainActivity :

    Activity(), Pikkel by PikkelDelegate() { var data by state<String?>(null) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) restoreInstanceState(savedInstanceState) } override fun onSaveInstanceState(outState: Bundle?) { super.onSaveInstanceState(outState) saveInstanceState(outState) } } ʢ΋͠อଘͯ͋͠Ε͹ʣ onCreate()ͷ savedInstanceState͔Β஋Λ ෮ݩ
  38. Copyright © Sansan, Inc. All rights reserved. > 公開しています。 -

    本体の実装は64⾏! - https://github.com/yamamotoj/Pikkel
  39. Copyright © Sansan, Inc. All rights reserved. > Thank you

    39