Slide 1

Slide 1 text

Copyright © Sansan, Inc. All rights reserved. > ObservableArray > Pikkel Jumpei Yamamoto 2016.7.1 第3回 Kotlin勉強会 in Sansan #kotlin_sansan

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Copyright © Sansan, Inc. All rights reserved. 3

Slide 4

Slide 4 text

Copyright © Sansan, Inc. All rights reserved. 4

Slide 5

Slide 5 text

Copyright © Sansan, Inc. All rights reserved. > Eightの新機能「オンライン名刺交換」 - もう紙の名刺はいらない! - NearByで周囲のEightユー ザーを検索 - 複数のユーザー間でも名刺 交換ができる

Slide 6

Slide 6 text

Copyright © Sansan, Inc. All rights reserved. > アジェンダ - ⾃作のライブラリを2つ紹介 - ObservableArray - Pikkel

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Copyright © Sansan, Inc. All rights reserved. > ObservableArray interface ObservableArray { val size: Int operator fun get(index: Int): T fun updates(): Observable 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] という形のアクセスが可能

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Copyright © Sansan, Inc. All rights reserved. > ObservableArray interface ObservableArray { val size: Int operator fun get(index: Int): T fun updates(): Observable 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を定義

Slide 13

Slide 13 text

Copyright © Sansan, Inc. All rights reserved. RecyclerViewの Adapterで使われることを想定 0CTFSWBCMF"SSBZ 変更の通知

Slide 14

Slide 14 text

Copyright © Sansan, Inc. All rights reserved. > ArrayListを使った実装 class ObservableArrayList( private val arrayList: ArrayList ) : ObservableArray { private val updateSubject = PublishSubject.create() 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)) }

Slide 15

Slide 15 text

Copyright © Sansan, Inc. All rights reserved. > ArrayListを使った実装 class ObservableArrayList( private val arrayList: ArrayList ) : ObservableArray { private val updateSubject = PublishSubject.create() 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Ͱ࣮૷

Slide 16

Slide 16 text

Copyright © Sansan, Inc. All rights reserved. > ArrayListを使った実装 class ObservableArrayList( private val arrayList: ArrayList ) : ObservableArray { private val updateSubject = PublishSubject.create() 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ΠϕϯτΛ ౤͛Δ

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Copyright © Sansan, Inc. All rights reserved. > operatorを拡張関数で追加 operator fun ObservableArray.plus(other: ObservableArray) : ObservableArray{ /* .... */ } // plusϝιουͰ + ԋࢉࢠͷ࣮૷Λஔ͖׵͑Δ val array1: ObservableArray() val array2: ObservableArray() val array3 = array1 + array2 // ࿈݁

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

Copyright © Sansan, Inc. All rights reserved. > operator fun plus()の実装 operator fun ObservableArray.plus(other: ObservableArray) : ObservableArray = object : ObservableArray { override val size: Int get() = [email protected] + other.size override fun get(index: Int): T { … } override fun updates(): Observable = Observable.merge( [email protected](), other.updates().map { val offset = [email protected] 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) } } ) }

Slide 26

Slide 26 text

Copyright © Sansan, Inc. All rights reserved. > operator fun plus()の実装 operator fun ObservableArray.plus(other: ObservableArray) : ObservableArray = object : ObservableArray { override val size: Int get() = [email protected] + other.size override fun get(index: Int): T { … } override fun updates(): Observable = Observable.merge( [email protected](), other.updates().map { val offset = [email protected] 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

Slide 27

Slide 27 text

Copyright © Sansan, Inc. All rights reserved. > operator fun plus()の実装 operator fun ObservableArray.plus(other: ObservableArray) : ObservableArray = object : ObservableArray { override val size: Int get() = [email protected] + other.size override fun get(index: Int): T { … } override fun updates(): Observable = Observable.merge( [email protected](), other.updates().map { val offset = [email protected] 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ΛͣΒ͢

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Copyright © Sansan, Inc. All rights reserved. 29 +

Slide 30

Slide 30 text

Copyright © Sansan, Inc. All rights reserved. > Eightでの使っているところ 30 ユーザー通知⽤ Item オンメモリ 投稿⽤ Item (固定) フィード表⽰⽤ Item Realm それぞれをObservableArrayとして それを合成

Slide 31

Slide 31 text

Copyright © Sansan, Inc. All rights reserved. > 公開してます - 本体の実装は50⾏! - https://github.com/yamamotoj/ObservableArray

Slide 32

Slide 32 text

> Pikkel

Slide 33

Slide 33 text

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ͷػೳΛ͔࣮ͭͬͯ૷ͯ͠Έͨ

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

Copyright © Sansan, Inc. All rights reserved. class MainActivity : Activity(), Pikkel by PikkelDelegate() { var data by state(null) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) restoreInstanceState(savedInstanceState) } override fun onSaveInstanceState(outState: Bundle?) { super.onSaveInstanceState(outState) saveInstanceState(outState) } } ʢ΋͠อଘͯ͋͠Ε͹ʣ onCreate()ͷ savedInstanceState͔Β஋Λ ෮ݩ

Slide 38

Slide 38 text

Copyright © Sansan, Inc. All rights reserved. > 公開しています。 - 本体の実装は64⾏! - https://github.com/yamamotoj/Pikkel

Slide 39

Slide 39 text

Copyright © Sansan, Inc. All rights reserved. > Thank you 39