Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Cycle for Android
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Jaewe Heo
August 03, 2016
Programming
2k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Cycle for Android
functional and reactive programming in Kotlin
Jaewe Heo
August 03, 2016
More Decks by Jaewe Heo
See All by Jaewe Heo
Kotlin, Gradle and AWS SAM
importre
1
660
Kotlin-Flavored BuildScripts
importre
1
380
A tour of Standard Library
importre
0
160
Compose everything with rx & kotlin
importre
0
1.4k
Ready for Production
importre
2
340
Other Decks in Programming
See All in Programming
難しいけど、読めた。- OSSの入口に立った話。
sts11142
0
150
残高管理から台帳サービスへの進化
artoy
1
190
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
160
Verilogで学ぶCPU自作入門
uyuki234
8
4.1k
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Rails World 2026, Austin, Texas
marcoroth
0
210
機械に任せるテスト、人が見るテスト ⽣成AIで引き直した、運⽤保守フェーズの線引き
dske104
0
180
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
1
300
外から家のPCの電源入れたい!をPHPで解決する
kawashimo0
1
130
golang-bob.pdf
iwatsukayura
0
130
Turning Architecture into Unit Tests in the AI Era (NSSpain XIV)
steliosf
PRO
1
140
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
640
AI時代のコードレビューは人に向けるな、仕組みに向けろ
texmeijin
5
3.6k
Featured
See All Featured
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
850
Java REST API Framework Comparison - PWX 2021
mraible
34
9.8k
How to Talk to Developers About Accessibility
jct
2
570
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.5k
Building Flexible Design Systems
yeseniaperezcruz
330
41k
Skip the Path - Find Your Career Trail
mkilby
1
250
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
2
940
Measuring & Analyzing Core Web Vitals
bluesmoon
9
1k
A designer walks into a library…
pauljervisheath
211
25k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
550
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
58k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
530
Transcript
Cycle for Android Jaewe Heo · !iiid! · @importre Aug.
3, 2016 functional and reactive programming in Kotlin
import importre
About me • Android • Rx • Kotlin - Kotlin
Korea • Electron - Electron Korea • React - react-photonkit • Alfred workflows
alfred-mdi
alfred-pg
alfred-gi
alfred-hl
alfred-awe
alfred-tidy
Cycle for Android functional and reactive programming in Kotlin
Cycle.js http://cycle.js.org/
HCI (Human-Computer Interaction) two-way process
None
None
None
Mutual observation Reactive Programming
Two-way process val y = human(x)
Two-way process val y = human(x) val x = computer(y)
Two-way process val y = human(x) val x = computer(y)
?!
val x = computer(human(x))
Streams
Programming Foo Bar
Programming Foo Bar
Programming Foo Bar
Imperative Programming Foo Bar Proactive Passive Fooо Bar ࢚కܳ ߸҃ೡ
ࣻ . Barח ־о ೱਸ ח ݽܲ.
// This is inside the `Foo` module fun onNetworkRequest() {
// ... bar.incrementCounter() // ... } Example of the Imperative Programming
Barח ৻ࠗ ߮ী ߈ೞৈ न ࢚కܳ ҙܻೠ. Reactive Programming Foo
Bar Listenable Reactive Fooח ־ҳীѱ ೱਸ ח ݽܲ.
// This is inside the `Bar` module foo.addOnNetworkRequestListener { //
`this` is Bar this.incrementCounter() } Example of the Reactive Programming
Solve the cyclic dependency val y = human(x) val x
= computer(y)
Solve the cyclic dependency val proxyX = ReplaySubject.create<Any>() val y
= human(proxyX) val x = computer(y)
Solve the cyclic dependency val proxyX = ReplaySubject.create<Any>() val y
= human(proxyX) val x = computer(y) x.imitate(proxyX)
None
kotlin-cycle Cycle for Android (written in Kotlin)
Hello Example • ܴਸ ੍ (read) • ݫद ߸҃ (model)
• ݫदܳ ചݶী ࠁৈષ (write)
None
HelloActivity.kt class HelloActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) setContentView(R.layout.activity_hello) Cycle.run(main, DomSource()) } private val main = { sources: Sources -> val change = sources.dom().select(helloEdit).textChanges() val model = change.map(::greeting) val view = model.map { message -> onUpdateView(message) } Sinks(DomSink(view)) } private fun onUpdateView(message: CharSequence) = { helloText.text = message } }
HelloActivity.kt class HelloActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) setContentView(R.layout.activity_hello) Cycle.run(main, DomSource()) } private val main = { sources: Sources -> val change = sources.dom().select(helloEdit).textChanges() val model = change.map(::greeting) val view = model.map { message -> onUpdateView(message) } Sinks(DomSink(view)) } private fun onUpdateView(message: CharSequence) = { helloText.text = message } }
HelloActivity.kt class HelloActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) setContentView(R.layout.activity_hello) Cycle.run(main, DomSource()) } private val main = { sources: Sources -> val change = sources.dom().select(helloEdit).textChanges() val model = change.map(::greeting) val view = model.map { message -> onUpdateView(message) } Sinks(DomSink(view)) } private fun onUpdateView(message: CharSequence) = { helloText.text = message } }
Kotlin-flavored Examples
HelloCycleActivity.kt class HelloCycleActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) setContentView(R.layout.activity_hello) cycle { val change = dom.select(helloEdit).textChanges() val model = change.map(::greeting) model.map { message -> { helloText.text = message } } } } }
HelloCycleActivity.kt class HelloCycleActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) setContentView(R.layout.activity_hello) cycle { val change = dom.select(helloEdit).textChanges() val model = change.map(::greeting) model.map { message -> { helloText.text = message } } } } }
Hello.kt fun greeting(name: CharSequence) = "Hello, $name!"
HelloTest.kt class HelloTest { @Test fun testGreeting() { val actual
= greeting("cycle") val expected = "Hello, cycle!" assertEquals(expected, actual) } }
BMI Example • ރޖѱ, ఃী ೠ ୡӝ ч ࢸ (properties)
• SeekBarܳ (read) • BMI ҅ • Ѿҗܳ ചݶী ࠁৈષ (write)
BmiActivity.kt cycle { val weightProps = Observable.just(Props(min = 40, max
= 140, value = 70)) val heightProps = Observable.just(Props(min = 140, max = 210, value = 170)) // Intent val (weightStream, heightStream) = intent(dom, heightProps, weightProps) // Model val stateStream = model(weightStream, heightStream, weightProps, heightProps) // View stateStream.map { state -> onUpdateView(state) } }
None
BmiActivity.kt private val intent = { dom: DomSource, heightProps: Observable<Props>,
weightProps: Observable<Props> -> val weightChangeStream = dom .select(weightSeekBar.apply { val props = weightProps.toBlocking().first() max = props.max - props.min progress = props.value - props.min }) .userChanges() val heightChangeStream = dom .select(heightSeekBar.apply { val props = heightProps.toBlocking().first() max = props.max - props.min progress = props.value - props.min }) .userChanges() Pair(weightChangeStream, heightChangeStream) }
BmiActivity.kt private val model = { weightChangeStream: Observable<Int>, heightChangeStream: Observable<Int>,
weightProps: Observable<Props>, heightProps: Observable<Props> -> Observable.combineLatest( weightChangeStream, heightChangeStream, weightProps, heightProps, ::calculateBmi) }
BmiActivity.kt private fun onUpdateView(state: State) = { unwrap(weightText, heightText, bmiText)
{ w, h, b -> w.text = "Weight: ${state.weight} kg" h.text = "Height: ${state.height} cm" b.text = "Bmi: ${state.bmi}" } nah { toast(R.string.error_undefined_views) } } kotlin-unwrap
Bmi.kt data class State(val weight: Int, val height: Int, val
bmi: Int) data class Props(val min: Int, val max: Int, val value: Int) fun calculateBmi(weight: Int, height: Int, weightProps: Props, heightProps: Props): State { val realHeight = height + heightProps.min val realWeight = weight + weightProps.min val heightMeters = realHeight * 0.01F val bmi = Math.round(realWeight / (heightMeters * heightMeters)) return State(realWeight, realHeight, bmi) }
REST Example • ࢜۽Ҋஜ (read) • ୡӝীח ࢜۽Ҋஜ হ ࢲߡ۽
ࠗఠ ؘఠܳ ੍যঠ ೣ • request(write) data -> response(read) data • Ѿҗܳ ചݶী ࠁৈષ (write) • ߡౡਸ ־ܴ (read) • షझܳ ڸ (write) https://jsonplaceholder.typicode.com/
UsersActivity.kt cycle { error = onError // Intent val usersStream
= api.getUsers() val refreshStream = dom .select(refreshView) .refreshes() .startWith(null as Void?) // Model val modelStream = Observable .combineLatest(usersStream, refreshStream) { users, refresh -> users } // View modelStream.map { users -> onUpdateView(users) } }
Extensions fun ImageView.loadUrl(imageUrl: String) = Picasso.with(context).load(imageUrl).into(this) fun Activity.toast(@StringRes id: Int)
= Toast.makeText(this, id, Toast.LENGTH_SHORT).show() fun Activity.toast(message: String) = Toast.makeText(this, message, Toast.LENGTH_SHORT).show() fun RecyclerView.ViewHolder.toast(message: String) = Toast.makeText(itemView.context, message, Toast.LENGTH_SHORT).show()
UserViewHolder.kt itemView.locationImage.loadUrl(url) itemView.nameText.text = user.name cycle { val emailChange =
dom.select(itemView.emailButton).clicks().map { ButtonType.EMAIL } val callChange = dom.select(itemView.callButton).clicks().map { ButtonType.CALL } val change = Observable.merge(emailChange, callChange) change.map { type -> show(user, type) } }
UserViewHolder.kt private fun show(user: User, type: ButtonType) = { toast(when
(type) { ButtonType.EMAIL -> user.email ButtonType.CALL -> user.phone }) }
Conclusion
Conclusion • ӭՔೞפ જӟೠؘ…
Conclusion • functional ೠо? • reactive ೠо? • productionী ਊ
оמೠо?
Conclusion • functional ೠо? • reactive ೠо? • productionী ਊ
оמೠо?
References
References - importre • https://github.com/importre/kotlin-cycle • https://github.com/importre/kotlin-unwrap • https://github.com/importre/ready-for-production •
Data class and Equality • Function Literals with Receiver • let, with, run, apply, use(using)
References - cycle.js • http://cycle.js.org/ • https://github.com/cyclejs-community/cycle-android
References - video • Unidirectional data flow architectures • What
if the user was a function?
val coWorker = true cycle { val change = dom
.select(toggle.apply { isChecked = true }) .checkedChanges() val model = change .map { onOff -> "উ٘۽٘ ѐߊܳ ݽभפ: $onOff" } .map { recruit -> "Riiid!\n$recruit" } model.map { message -> { checkText.text = message } } }
[email protected]
Thank you