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
h

Hachemi Hamadi

12/15/2021, 11:30 AM
Hello, I am facing weird issue on some devices (Xiaomi mainly). Here is the output of the error stack :
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.cardshop.app.compose, PID: 12745
    java.lang.IllegalStateException: measure() may not be called multiple times on the same Measurable
        at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:86)
        at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:71)
        at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1293)
        at androidx.compose.foundation.layout.RowColumnImplKt$rowColumnMeasurePolicy$1.measure-3p2s80s(RowColumnImpl.kt:89)
        at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:51)
        at androidx.compose.foundation.ScrollingLayoutModifier.measure-3p2s80s(Scroll.kt:342)
        at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:39)
        at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:131)
        at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:131)
        at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:131)
        at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:131)
        at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:131)
        at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:131)
        at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:306)
        at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:39)
        at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:131)
        at androidx.compose.foundation.layout.PaddingModifier.measure-3p2s80s(Padding.kt:364)
        at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:39)
        at androidx.compose.foundation.layout.FillModifier.measure-3p2s80s(Size.kt:658)
        at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:39)
        at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:100)
        at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:99)
        at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:126)
        at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:88)
        at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:76)
        at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:99)
        at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.kt:1302)
        at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release$default(LayoutNode.kt:1298)
        at androidx.compose.ui.node.LayoutNode.onBeforeLayoutChildren(LayoutNode.kt:1080)
        at androidx.compose.ui.node.LayoutNode.layoutChildren$ui_release(LayoutNode.kt:961)
        at androidx.compose.ui.node.LayoutNode.onNodePlaced$ui_release(LayoutNode.kt:954)
        at androidx.compose.ui.node.InnerPlaceable.placeAt-f8xVGno(InnerPlaceable.kt:125)
        at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:31)
        at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50(Placeable.kt:370)
        at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50$default(Placeable.kt:203)
        at androidx.compose.ui.node.DelegatingLayoutNodeWrapper$measure$1$1.placeChildren(DelegatingLayoutNodeWrapper.kt:138)
        at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.placeAt-f8xVGno(DelegatingLayoutNodeWrapper.kt:126)
        at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:31)
        at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50(Placeable.kt:370)
🧵 2
:thread-please: 2
l

loloof64

12/15/2021, 12:11 PM
Are you trying to define a custom layout ?
h

Hachemi Hamadi

12/15/2021, 12:15 PM
@loloof64 No, the UI is basically a Column with Text and TextField to enter email address. And a Button.
l

loloof64

12/15/2021, 12:17 PM
Ok sorry. I may not be of good help, but could you share the
@Composable
or snippet of the
@Composable
which has issue ?
h

Hachemi Hamadi

12/15/2021, 12:20 PM
enum class SignupEmailVerification {
    ENTER_EMAIL, EMAIL_SENT
}

@OptIn(ExperimentalPagerApi::class, ExperimentalComposeUiApi::class)
@Composable
fun SignupEmail(pagerState: PagerState, authViewModel: AuthViewModel) {

    val confirmText = stringResource(R.string.confirm_text)


    val scope = rememberCoroutineScope()
    var emailValue by remember { mutableStateOf("") }
    var nextButtonText by remember { mutableStateOf(confirmText) }
    var emailValueErrorState by remember { mutableStateOf(false) }
    var signupEmailStep by remember { mutableStateOf(SignupEmailVerification.ENTER_EMAIL) }
    
    val isSendingEmail by authViewModel.isSendingEmailOtp.observeAsState(false)
    val emailOtpSent by authViewModel.emailOtpSent.observeAsState(false)
    val emailOtpError by authViewModel.emailOtpError.observeAsState(false)


    val emailCode = remember { mutableStateOf("") }

    val keyboardController = LocalSoftwareKeyboardController.current

    val appContext = LocalContext.current

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(start = 24.dp, end = 24.dp)
            .verticalScroll(rememberScrollState()),
        verticalArrangement = <http://Arrangement.Top|Arrangement.Top>,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Spacer(modifier = Modifier.height(24.dp))
        Text(
            text = stringResource(R.string.signup_what_is_your_email),
            modifier = Modifier.fillMaxWidth(),
            textAlign = TextAlign.Start,
            color = Black,
            style = TextStyle(fontSize = 24.sp, fontWeight = FontWeight.W600)
        )
        Spacer(modifier = Modifier.height(8.dp))

        TextField(
            modifier = Modifier.fillMaxWidth(),
            value = emailValue,
            placeholder = { Text(text = "Email") },
            colors = TextFieldDefaults.textFieldColors(
                cursorColor = Black,
                backgroundColor = Color(0xFFF1F3FD),
                focusedIndicatorColor = Color.Transparent,
                unfocusedIndicatorColor = Color.Transparent,
                disabledIndicatorColor = Color.Transparent
            ),
            onValueChange = {
                if (emailValueErrorState) emailValueErrorState = !emailValueErrorState
                emailValue = it
            },
            isError = emailValueErrorState,
            enabled = !emailOtpSent,
            shape = RoundedCornerShape(4.dp),
            singleLine = true,
            textStyle = LocalTextStyle.current.copy(color = Black),
            keyboardOptions = KeyboardOptions(
                keyboardType = KeyboardType.Email,
            ),
            trailingIcon = {
                if (emailValue.isNotEmpty()) {
                    IconButton(onClick = when (emailOtpSent) {
                        true -> {
                            { }
                        }
                        else -> {
                            { emailValue = "" }
                        }
                    }) {
                        Icon(
                            imageVector = Icons.Outlined.Close,
                            contentDescription = null
                        )
                    }
                }
            }
        )
        Text(
            text = stringResource(R.string.signup_you_needto_comfirm_text),
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 4.dp),
            textAlign = TextAlign.Start,
            style = TextStyle(color = Black, fontSize = 14.sp)
        )
        Spacer(modifier = Modifier.height(32.dp))

        // After the email is sent
        if (emailOtpSent) {
            nextButtonText = stringResource(R.string.next_text)
            signupEmailStep = SignupEmailVerification.EMAIL_SENT
            Text(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(horizontal = 8.dp),
                text = stringResource(R.string.signup_enter_otp_sent_to_text),
                textAlign = TextAlign.Start,
            )
            Text(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(horizontal = 8.dp),
                text = emailValue,
                textAlign = TextAlign.Start,
            )
            Spacer(modifier = Modifier.height(32.dp))

            TechsioOtpComponent(otpValue = {
                emailCode.value = it
            })

            Spacer(modifier = Modifier.height(32.dp))
        }

        Button(
            onClick = {
                // Hide the virtual keyboard
                keyboardController?.hide()

                if (signupEmailStep == SignupEmailVerification.ENTER_EMAIL) {
                    // Check is correct email schema
                    if (!Patterns.EMAIL_ADDRESS.matcher(emailValue).matches()) {
                        emailValueErrorState = true
                    } else {
                        // send the email verification
                        authViewModel.sendSignupEmailOtp(emailValue = emailValue)
                    }
                } else {
                    // construct a list of not NULL values
                    if (emailCode.value.length == 6) {
                        authViewModel.setSignupUserValue(
                            email = emailValue,
                            otp = emailCode.value
                        )
                        // Change to previous step
                        signupEmailStep = SignupEmailVerification.ENTER_EMAIL
                        scope.launch {
                            pagerState.animateScrollToPage(1)
                        }

                    } else {
                        Toast.makeText(
                            appContext,
                            "Email code is not correct",
                            Toast.LENGTH_SHORT
                        ).show()
                    }
                }
            },
            colors = ButtonDefaults.buttonColors(
                disabledBackgroundColor = Color.Gray
            ),
            enabled = !isSendingEmail,
            modifier = Modifier,
            shape = RoundedCornerShape(4.dp)
        ) {
            if (isSendingEmail) CircularProgressIndicator()
            else Text(
                text = nextButtonText,
                modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
                style = MaterialTheme.typography.h6.copy(color = whiteColor)
            )
        }
    }

}
f

Filip Wiesner

12/15/2021, 3:46 PM
It's maybe this bug in compose? I see pager state and that's implemented using LazyColumn I believe so it could be related