Slide 1

Slide 1 text

Data Binding with RecyclerView Keisuke Kobayashi / @kobakei shibuya.apk #16

Slide 2

Slide 2 text

About me • Keisuke Kobayashi • GitHub, Qiita: @kobakei • Twitter: @kobakei122 • Kyash, Inc

Slide 3

Slide 3 text

ࠓ೔࿩͢͜ͱ • σʔλόΠϯσΟϯάΛRecyclerViewͰ࢖͏ ࿩Λ͠·͢

Slide 4

Slide 4 text

DroidKaigi
 Contributors List

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

ྫ: DroidKaigi contributors list • ը໘શମ • ϢʔβʔϦετ • ΞΠςϜ • Ϣʔβʔ • ໊લ • ը૾URL

Slide 7

Slide 7 text

Files • ը໘શମ • user_list_activity.xml • UserListActivity • UserAdapter • UserListViewModel • ֤ΞΠςϜ • user_list_item.xml

Slide 8

Slide 8 text

Files • ը໘શମ • user_list_activity.xml • UserListActivity • UserAdapter • UserListViewModel • ֤ΞΠςϜ • user_list_item.xml

Slide 9

Slide 9 text

user_list_activity.xml • RecyclerViewΛஔ͚ͩ͘

Slide 10

Slide 10 text

user_list_item.xml • ֤Ϣʔβʔͱ֤ΞΠςϜͷόΠϯσΟϯά

Slide 11

Slide 11 text

user_list_item.xml • ֤Ϣʔβʔͱ֤ΞΠςϜͷόΠϯσΟϯά UserʹόΠϯυ

Slide 12

Slide 12 text

UserListViewModel • ͜͜Ͱ͸ϢʔβʔϦετ͸ݻఆ class UserListViewModel: BaseObservable() { val users = listOf( User(“taro”, “https://example.com/1.png”), User(“jiro”, “https://example.com/2.png”), User(“saburo”, “https://example.com/3.png”) ) }

Slide 13

Slide 13 text

UserListActivity lateinit var viewModel: UserListViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = DataBindingUtil.setContentView( this, R.layout.user_list_activity) // Set up viewModel here (ex. inject by Dagger) binding.recyclerView.setAdapter(UserAdapter(viewModel.users)) }

Slide 14

Slide 14 text

UserListActivity lateinit var viewModel: UserListViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = DataBindingUtil.setContentView( this, R.layout.user_list_activity) // Set up viewModel here (ex. inject by Dagger) binding.recyclerView.setAdapter(UserAdapter(viewModel.users)) } ը໘ͷϏϡʔϞσϧ ͜͜ͰॳظԽ

Slide 15

Slide 15 text

UserListActivity lateinit var viewModel: UserListViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = DataBindingUtil.setContentView( this, R.layout.user_list_activity) // Set up viewModel here (ex. inject by Dagger) binding.recyclerView.setAdapter(UserAdapter(viewModel.users)) } ը໘ͷϏϡʔϞσϧͷusersΛΞμϓλʔʹηοτ

Slide 16

Slide 16 text

UserAdapter class UserAdapter(val users: List): RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = UserListItemBinding.inflate(inflater, parent, false) return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val binding = holder.binding binding.user.set(users[position]) } }

Slide 17

Slide 17 text

UserAdapter class UserAdapter(val users: List): RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = UserListItemBinding.inflate(inflater, parent, false) return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val binding = holder.binding binding.user.set(users[position]) } } UserListItemBinding༻
 ViewHolder

Slide 18

Slide 18 text

UserAdapter class UserAdapter(val users: List): RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = UserListItemBinding.inflate(inflater, parent, false) return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val binding = holder.binding binding.user.set(users[position]) } } onBindViewHolderͰ
 ϢʔβʔΛηοτ͢Δ

Slide 19

Slide 19 text

ϢʔβʔϦετΛ
 APIͰऔಘ͢Δ৔߹͸ʁ

Slide 20

Slide 20 text

UserListViewModel class UserListViewModel(...): BaseObservable() { val users = mutableListOf() fun onStart() { // getUsers͸Single> getUsers().subscribe({ users.addAll(it) adapter.notifyDataSetChanged() }) } }

Slide 21

Slide 21 text

UserListViewModel class UserListViewModel(...): BaseObservable() { val users = mutableListOf() fun onStart() { // getUsers͸Single> getUsers().subscribe({ users.addAll(it) adapter.notifyDataSetChanged() }) } } ???

Slide 22

Slide 22 text

Ϧετͷมߋ௨஌ • ϏϡʔϞσϧ͕adapterΛ࣋ͭͷ͕ؾ࣋ͪѱ͍ • ObservableInt΍ObservableFieldΈ͍ͨͳ
 ௨஌ͷ࢓૊Έ͕ཉ͍͠ • ஋Ληοτ͢Δ͚ͩͰ௨஌͞Εͯ΄͍͠

Slide 23

Slide 23 text

ObservableList • android.databindingύοέʔδ • ௨஌ػೳͷ͋ΔϦετ • ObservableArrayListͰΠϯελϯεԽ

Slide 24

Slide 24 text

UserListViewModel class UserListViewModel: BaseObservable() { val users = ObservableArrayList() // Called from activity's onCreate fun initialize() { getUsers().subscribe({ users.addAll(it) }) } }

Slide 25

Slide 25 text

UserListViewModel class UserListViewModel: BaseObservable() { val users = ObservableArrayList() // Called from activity's onCreate fun initialize() { getUsers().subscribe({ users.addAll(it) }) } } ObservableList

Slide 26

Slide 26 text

UserListViewModel class UserListViewModel: BaseObservable() { val users = ObservableArrayList() // Called from activity's onCreate fun initialize() { getUsers().subscribe({ users.addAll(it) }) } } ͜Ε͚ͩͰOK

Slide 27

Slide 27 text

UserAdapter class UserAdapter(val users: ObservableList): RecyclerView.Adapter() { init { users.addOnListChangedCallback(object: ObservableList.OnListChangedCallback>() { override fun onChanged(users: ObservableList?) { notifyDataSetChanged() } ... }) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {...} override fun onBindViewHolder(holder: ViewHolder, position: Int) {...} }

Slide 28

Slide 28 text

UserAdapter class UserAdapter(val users: ObservableList): RecyclerView.Adapter() { init { users.addOnListChangedCallback(object: ObservableList.OnListChangedCallback>() { override fun onChanged(users: ObservableList?) { notifyDataSetChanged() } ... }) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {...} override fun onBindViewHolder(holder: ViewHolder, position: Int) {...} } ίϯετϥΫλͰObservableListΛड͚औΔ

Slide 29

Slide 29 text

UserAdapter class UserAdapter(val users: ObservableList): RecyclerView.Adapter() { init { users.addOnListChangedCallback(object: ObservableList.OnListChangedCallback>() { override fun onChanged(users: ObservableList?) { notifyDataSetChanged() } ... }) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {...} override fun onBindViewHolder(holder: ViewHolder, position: Int) {...} } ॳظԽ࣌ʹ ίʔϧόοΫొ࿥

Slide 30

Slide 30 text

UserAdapter class UserAdapter(val users: ObservableList): RecyclerView.Adapter() { init { users.addOnListChangedCallback(object: ObservableList.OnListChangedCallback>() { override fun onChanged(users: ObservableList?) { notifyDataSetChanged() } ... }) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {...} override fun onBindViewHolder(holder: ViewHolder, position: Int) {...} } ֤ίʔϧόοΫͰ
 notifyʙΛݺͿ

Slide 31

Slide 31 text

༨ஊ: ϕʔεΫϥεʹ͢Δ abstract class ObservableRecyclerAdapter( val items: ObservableList ): RecyclerView.Adapter() { init { items.addOnListChangedCallback(object: ObservableList.OnListChangedCallback>() { override fun onChanged(items: ObservableList?) { notifyDataSetChanged() } ... }) } }

Slide 32

Slide 32 text

༨ஊ: ϕʔεΫϥεʹ͢Δ abstract class ObservableRecyclerAdapter( val items: ObservableList ): RecyclerView.Adapter() { init { items.addOnListChangedCallback(object: ObservableList.OnListChangedCallback>() { override fun onChanged(items: ObservableList?) { notifyDataSetChanged() } ... }) } }

Slide 33

Slide 33 text

͜ΕͰϦετΛૢ࡞͢Δ͚ͩͰ
 ը໘ʹ൓ө͞ΕΔΑ͏ʹͳͬͨʂ

Slide 34

Slide 34 text

ͳΜ͔ͪΒͭ͘...

Slide 35

Slide 35 text

ͳͥʁ • όΠϯυର৅ͷΦϒδΣΫτͷมߋͷ
 ࣍ͷϑϨʔϜͰUI͕ߋ৽͞ΕΔ • SwipeRefreshLayoutͱͷ૊Έ߹ΘͤͰݦஶ • ͢ͰʹϏϡʔ͕࡞੒ࡁΈͷঢ়ଶͰɺ
 clear + addAll

Slide 36

Slide 36 text

UserAdapter class UserAdapter(val users: ObservableList): RecyclerView.Adapter() { init {...} override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder { ... } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val binding = holder.binding binding.user.set(users[position]) binding.executePendingBindings() } }

Slide 37

Slide 37 text

UserAdapter class UserAdapter(val users: ObservableList): RecyclerView.Adapter() { init {...} override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder { ... } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val binding = holder.binding binding.user.set(users[position]) binding.executePendingBindings() } } ͜ΕͰଈ࣌ʹUIߋ৽͞ΕΔʂ

Slide 38

Slide 38 text

ϦετͷΞΠςϜ಺ͷ
 Πϕϯτ

Slide 39

Slide 39 text

ྫ • ֤ΞΠςϜͷը૾ΛλοϓͰ֦େද͍ࣔͨ͠ • ͦΕҎ֎ͷ෦෼ΛλοϓͰɺৄࡉϓϩϑΟʔ ϧΛද͍ࣔͨ͠ • ListViewͳΒҎԼͰ΋OK
 android:onItemClick=“@{viewModel::onItemClick}”

Slide 40

Slide 40 text

ΫϦοΫͰ֦େ

Slide 41

Slide 41 text

ΫϦοΫͰৄࡉ΁

Slide 42

Slide 42 text

Files • ը໘શମ • user_list_activity.xml • UserListActivity • UserAdapter • UserListViewModel • ֤ΞΠςϜ • user_list_item.xml • UserViewModel ʢ֤ΞΠςϜͷϏϡʔϞσϧʣ

Slide 43

Slide 43 text

user_list_item.xml

Slide 44

Slide 44 text

user_list_item.xml ΞΠςϜ͝ͱͷ
 ϏϡʔϞσϧ

Slide 45

Slide 45 text

user_list_item.xml ΫϦοΫΠϕϯτΛ
 όΠϯυ

Slide 46

Slide 46 text

UserViewModel class UserViewModel: BaseObservable() { val user = ObservableField() fun onItemClick(view: View) { // go to profile } fun onImageClick(view: View) { // go to image viewer } }

Slide 47

Slide 47 text

UserAdapter class UserAdapter(val users: ObservableList): RecyclerView.Adapter() { init {...} override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = UserListItemBinding.inflate(inflater, parent, false) binding.viewModel = UserViewModel() return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val binding = holder.binding binding.viewModel.user.set(users[position]) binding.executePendingBindings() } }

Slide 48

Slide 48 text

UserAdapter class UserAdapter(val users: ObservableList): RecyclerView.Adapter() { init {...} override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = UserListItemBinding.inflate(inflater, parent, false) binding.viewModel = UserViewModel() return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val binding = holder.binding binding.viewModel.user.set(users[position]) binding.executePendingBindings() } } Ϗϡʔͷ࡞੒࣌ʹ
 ϏϡʔϞσϧΛηοτ

Slide 49

Slide 49 text

UserAdapter class UserAdapter(val users: ObservableList): RecyclerView.Adapter() { init {...} override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = UserListItemBinding.inflate(inflater, parent, false) binding.viewModel = UserViewModel() return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val binding = holder.binding binding.viewModel.user.set(users[position]) binding.executePendingBindings() } } ϏϡʔϞσϧͷ
 ϢʔβʔΛߋ৽

Slide 50

Slide 50 text

·ͱΊ • σʔλόΠϯσΟϯάΛRecyclerViewͰ࢖͏ ํ๏ͷ঺հ • ObservableList • executePendingBindings • ΞΠςϜ͝ͱʹϏϡʔϞσϧ

Slide 51

Slide 51 text

Thanks!