https://kotlinlang.org logo
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
benchmarks
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
confetti
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
lincheck
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by
Title
f

fal

08/17/2019, 6:53 PM
Am I the only soul on earth that finds the whole LiveData encapsulation atrocious to the eyes? I obviously understand why we only let 'LiveData' vars accessible and not mutable ones, but it honestly kills me inside to have repeated fields where one has prefixed '_', e.g.:
private val _navigateToSpeakerAction = MutableLiveData<Event<SpeakerId>>()
val navigateToSpeakerAction: LiveData<Event<SpeakerId>> = _navigateToSpeakerAction
it's so goddamn ugly.. i think i even prefer just a standalone getter
m

Mark Murphy

08/17/2019, 7:20 PM
The underscore-and-duplicate-name convention is a convention. If you can keep track of stuff, you are not obligated to follow that convention:
private val navAction = MutableLiveData<Event<SpeakerId>>()
val navigateToSpeakerAction: LiveData<Event<SpeakerId>> = navAction
There's also the custom getter option:
private val _navigateToSpeakerAction = MutableLiveData<Event<SpeakerId>>()
val navigateToSpeakerAction: LiveData<Event<SpeakerId>>
  get() = _navigateToSpeakerAction
If you are not referencing the
MutableLiveData
(as that type) from many places, you could go with a single property and a cast:
val navigateToSpeakerAction: LiveData<Event<SpeakerId>> = MutableLiveData<Event<SpeakerId>>()

// somewhere later

(navigateToSpeakerAction as MutableLiveData<Event<SpeakerId>>).value = TODO("something")
On one project that I worked on, a developer had us extend all our
ViewModel
classes from a
BaseViewModel
that had protected extension functions on
LiveData
that would perform that casting for us:
protected fun <T> LiveData<T>.update(value: T?) {
    (this as MutableLiveData).value = value
}
Then, the
BaseViewModel
subclasses could just have:
navigateToSpeakerAction.update(TODO("something"))
So, there are a variety of options. None are the prettiest, but perhaps one looks better to you than the others...
👍 3
f

fal

08/17/2019, 7:25 PM
I realize it's a convention, just not a very pretty one to me 😛 but thanks for different alternatives! I actually find the last one you provided interesting
👍 1
p

Pablichjenkov

08/17/2019, 7:27 PM
Don't feel alone. On my personal opinion we don't need LiveData. It just add ceremony to an RxStream or a Coroutine cluster.
m

Mark Murphy

08/17/2019, 7:31 PM
That last one worked reasonably well and has the least per-
LiveData
syntactical overhead. It does require the common base class though, so the extension functions can only be used from the "owners" of the
MutableLiveData
. I keep thinking that there could be some sort of property delegate approach here, but I have never figured one out.
👍 1
f

fal

08/17/2019, 7:41 PM
@Pablichjenkov on that note, I would love to have a full coroutine example app to mess around with. I'm very used to Rx, and while I realize we could replace LiveData with ConflatedBroadcastChannel & regular channels, I'm so new to it that I don't know how to wire them up... Still searching for that example app..
👍 1
a

Adam Powell

08/17/2019, 8:03 PM
If you're used to Rx but still want to use LiveData as a last-mile for UI, check out the
liveData
builder in the ktx libraries. It's more or less a coroutine-based
Observable.create
for LiveData.
👍 1
If you come from more of an Rx background,
MutableLiveData
is basically a
BehaviorSubject
, it has fairly limited use and the primary one is to bridge into streaming/observable code from outside. The pattern that started this thread is exceedingly rare outside of getting started cases.
m

Mark Murphy

08/17/2019, 8:12 PM
liveData {}
is in an alpha release right now, which means that it is unavailable to projects that avoid pre-release dependencies. I think
MutableLiveData
is fairly popular, though some of those use cases will be able to be replaced with
liveData {}
in time.
a

Adam Powell

08/17/2019, 8:16 PM
Sure, but
liveData {}
is certainly the direction in which we're headed. There are a few Flow interop extensions that just went in recently based on it too.
1
m

Mark Murphy

08/17/2019, 8:17 PM
Yep, and I'm looking forward to them! "The future is here, it's just not evenly distributed", and all that.
a

Adam Powell

08/17/2019, 8:17 PM
(also, hey @Mark Murphy, how've you been? 😁)
m

Mark Murphy

08/17/2019, 8:19 PM
(doing fine -- hope life is treating you well!)
a

Adam Powell

08/17/2019, 8:19 PM
It is, thanks!
I mean, if someone says the MutableLiveData scoping dance is ugly I'm not going to argue, it's absolutely true and the official answer to that is
liveData {}
🙂 I imagine we're going to put it up for stable channel once some folks are back from summer vacations
👍 1
2
p

Pablichjenkov

08/17/2019, 8:38 PM
You guys sound
coworkers
😸 Anyways, what I found a bit verbose is the fact of mapping and re-publishing my Rx-Events to liveData events, specially when dealing with Exception -> Errors. Hopefully this
liveData {...}
directive helps on that. @fal, you said it right, when dealing with coroutines you can use a ConflatedBroadcastChannel or regular channel in the last mile. I wish some influencer makes a good standard sample but as of now we just have that. There are many designs, one could be having a
coroutineScope
living in your View, this one setup with a dispatcher on the UI thread. Then have a channel living in your View too and call
channel.consumeEach()
under this coroutineScope. Assuming your ViewModel will be basically a coroutineScope then you can pass your channel as a
SendChannel
and the ViewModel will put events into it.
👍 1
a

Adam Powell

08/17/2019, 8:44 PM
You'll get more or less equivalent patterns from
ConflatedBroadcastChannel
for the producer and
.asFlow()
as the consumer that you get from [Mutable]LiveData. Flow makes a much better subscriber endpoint than raw channels do since you don't have to remember to close them.
👍 2
p

Pablichjenkov

08/17/2019, 8:51 PM
Definitely Flow for better and cleaner.
f

fal

08/17/2019, 8:52 PM
@Pablichjenkov yep! I'm going to investigate channels further soon enough
@Adam Powell Thanks! I realize that livedata is similar to BehaviorSubject... Where I work I still use MVP with Rx (it works for our purposes and it's an old big project so refactoring is hard). For my projects, however, I want to explore the latest trends. Ideally I'd like to have a full coroutine/flow project but it's still not very clear to me how it all works and how it wires up together (hence the need for a complete example). Most examples out there are not very complete so it's hard for me to visualize what is the functional equivalent of the Rx way in certain scenarios on architecture
p

Pablichjenkov

08/17/2019, 8:57 PM
I have some code with that design I talked to you. Mainly influenced by my trauma with Actors. Unfortunately I used
actor { ... }
builder a lot. It is obsolete now. However, as Adam suggested Flow is cleaner for API design
f

fal

08/17/2019, 8:59 PM
@Pablichjenkov does flow eliminate the need to use channels in most cases?
p

Pablichjenkov

08/17/2019, 9:03 PM
It depends on your use case. They are both structured concurrency primitives. In the reactive theory Flow is a cold source while channel is more of a hot source. Some Flow Operators(Source -> Sink) uses channel internally to buffer, merge and many other good stuff you can do with it.
For a more comprehensive explanation about suspend functions, CoroutineScope/CoroutineContext, Channels and Flow I advice you follow Roman Elizarov on medium. Start reading his articles sorted by date. Of course staying tuned to this channel is golden too.
a

Adam Powell

08/17/2019, 9:14 PM
yeah Roman's stuff is great
if you already know Rx, Flow = Flowable, more or less
basically, here's your equivalents:
val disposable = launch {
  try {
    // implicit request(1) on initial collect
    myFlow.collect {
      onNext(it)
      // implicit request(1) on return
      // or throw CancellationException to cancel
    }
    onComplete()
  } catch (ce: CancellationException) {
    throw ce // pass cancellation through
  } catch (t: Throwable) {
    onError(t)
  }
}
p

Pablichjenkov

08/17/2019, 9:19 PM
Flow = Flowable
Now I know where they picked the name from. Initially I thought they stole the term from AKKA-streams. Just in general, the Coroutine API is wider than RxJava, you can say that Flow is the Reactive-Stream side of it.
a

Adam Powell

08/17/2019, 9:35 PM
also
java.util.concurrent.Flow
🙂
f

fal

08/17/2019, 9:45 PM
Thanks a lot @Pablichjenkov @Adam Powell! I'll be diving into it very soon and this is all very helpful already 👍
👍 1
p

Pablichjenkov

08/17/2019, 9:46 PM
that’s right 🤓. The future sounds like it’s gonna be Flow party. Hopefully all frameworks implement pretty much the same concept and not miss-use the term to represent something totally different. at Francisco no problem at all
a

Adam Powell

08/17/2019, 10:01 PM
fwiw, recently merged into androidx libraries:
Flow<T>.asLiveData(): LiveData<T>
and
LiveData<T>.asFlow(): Flow<T>
https://android-review.googlesource.com/c/platform/frameworks/support/+/1096457 https://android-review.googlesource.com/c/platform/frameworks/support/+/1098315
👍 6
r

rkeazor

08/18/2019, 10:52 AM
Remember there is Transformations.switchMap ,Transformations.map , and MedatatorLiveData that all return LiveDatat object..