2026/03/07

오늘의 이야기

앱에서 알림을 구현하는 방법은 여러 가지가 있다. alertDiaglog을 이용하는 방법도 있기는 하지만, 요새는 SnackBar을 구현하는 경우가 많은 것 같다. Jetpack Compose에서는 아직 잘 모르겠는 부분이 있어서 구글을 하다 찾아보게 되었다.


 


https://stackoverflow.com/questions/68909340/how-to-show-snackbar-with-a-button-onclick-in-jetpack-compose



 


How to show snackbar with a button onclick in Jetpack Compose


I want to show snackbar with a button onclick in Jetpack Compose I tried this Button(onClick = { Snackbar(action = {}) { Text("hello") } } But AS said "@Composable


stackoverflow.com




 


이제 실전으로 갈 볼까 ? 먼저 위 글에서 퍼온 코드를 일부 수정해서 공통적으로 사용할 수 있도록 준비를 해 보아야겠다.


 


import android.annotation.SuppressLint
import android.util.Log
import androidx.compose.material.Scaffold
import androidx.compose.material.SnackbarResult
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import kotlinx.coroutines.launch

@SuppressLint("UnusedMaterialScaffoldPaddingParameter", "CoroutineCreationDuringComposition")
@Composable
fun SnackBarShow(
message:String, actionLabel: String,
doDismissed:() -> Unit,
doActionPerformed:() -> Unit
) {
val scaffoldState = rememberScaffoldState() // this contains the `SnackbarHostState`
val coroutineScope = rememberCoroutineScope()

Scaffold(
modifier = Modifier,
scaffoldState = scaffoldState // attaching `scaffoldState` to the `Scaffold`
) {
coroutineScope.launch {
// using the `coroutineScope` to `launch` showing the snackbar
// taking the `snackbarHostState` from the attached `scaffoldState`
val snackbarResult = scaffoldState.snackbarHostState.showSnackbar(
message = message,
actionLabel = actionLabel
)
when (snackbarResult) {
SnackbarResult.Dismissed -> {
Log.e("SnackBarShow", "Dismissed")
doDismissed()
}
SnackbarResult.ActionPerformed -> {
Log.e("SnackBarShow", "SnackBar's button clicked")
doActionPerformed()
}
}
}
}
}

코드를 일부 동작할 수 있도록 수정했다.  @SuppressLint("UnusedMaterialScaffoldPaddingParameter", "CoroutineCreationDuringComposition")는 코드에서 오류 표시가 나는 것 때문에 수정을 하기는 했다. Padding Parameter을 사용하지 않는 것과 DuringComposition 부분인 것 같기는 하지만, 아직은 잘 모른다.


 


그리고 doDismissed(), doActionPerformed() 함수는 화면의 버튼을 클릭 했을 때 동작을 처리하는 부분을 구현해야 하기 때문에 return 될 함수의 선언으로 추가해 주었다.


 


이제 MainActivity 에서 코드를 구현해 보아야겠다.


 


setContent{
SnackBarShow(
getString(R.string.msgFinish), getString(R.string.titleFinish),
doDismissed = {},
doActionPerformed = {
finish()
}
)
}

어디에서는 간에 setCotent 로 감싸고 나서 위에서 작성한 SnackBarShow을 호출해 주는 것이다. 파라미터는 메시지로 보여줄 것과 버튼에 들어갈 문구를 전달하고 return 되는 함수는 SnackBar의 버튼을 클릭하지 않은 경우 처리와 , 버튼을 클릭했을 때 사용할 처리를 위해서 구현한 함수 2개를 돌려받았다.


 


실행이미지



 





오늘의 이야기

https://flatteredwithflutter.com/using-compose-destinations%ef%bf%bc/



 


Using compose destinations


We will cover briefly: Current navigation in composeUsing compose destinations(Optional) Modify existing test cases Current navigation in compose We get Compose Navigation from the Jetpack Com…


flatteredwithflutter.com




navigation 의 첫 이야기 다음... 그것을 어떻게 풀어낼 것인가를 찾아 돌아다니다가 또 하나의 링크를 찾았다. 이것을 보면서 이해를 하기 시작해 본다. 


 


그래서 오늘은 따라해 보기를 해 보아야겠다.


 


먼저 build gradle 에 설정을 따라해 본다. 


 


plugins {
...
id 'com.google.devtools.ksp' version '1.7.0-1.0.6'
}

1.7.0-1.0.6 은 코틀린 버전과 연계가 되어야 하는 버전을 맞추어 주는 것으로 이해를 하였다. 코틀린이 1.7.10까지 패치가 되어 가는 것 같기는 하지만, 일단 확인된 바로는 1.7.0 까지 인 것 같아서...


 


android {

...

applicationVariants.all { variant ->
kotlin.sourceSets {
getByName(variant.name) {
kotlin.srcDir("build/generated/ksp/${variant.name}/kotlin")
}
}
}

kotlin.sourceSets.all {
languageSettings.optIn("kotlin.RequiresOptIn")
}

...

}

이 부분이 들어가면 gradle 빌드를 통해서 kotlin 이라는 폴더가 생기면서 필요한 class 등을 만들어 주는 경로를 설정하는 것으로 이해가 되었다.


 


dependencies {

...
// compose destination
// https://github.com/raamcosta/compose-destinations 에서 최종 버전을 확인
implementation 'io.github.raamcosta.compose-destinations:animations-core:1.7.15-beta'
ksp 'io.github.raamcosta.compose-destinations:ksp:1.7.15-beta'
implementation "androidx.hilt:hilt-navigation-compose:1.0.0"

}

다음은 implementation  을 선언해 주는 것인데, 버전 확인은 원작자의 github 에서 확인하여 수정하면 최신 버전이 사용될 것 같다. 


 


다음은 activity 을 만들어 주어야 하는 데... 지금은 테스트 하는 것이기 때문에 간단하게 수정해 보았다.


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

doUpdateCheck()

setContent {

MainTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = softBlue
) {
// github 에서 본 것 처럼 추가.
val navHostEngine = rememberAnimatedNavHostEngine()
DestinationsNavHost(navGraph = NavGraphs.root, engine = navHostEngine)

}
}
}
}

이렇게 추가를 해 주고 나면 NavGraphs 가 생성이 되지 않아서 오류 표시가 나오지만, 일단은 무시하고 화면을 구성할 부분을 만들어 주었다.


 


@Destination(start = true)
@Composable
fun LoginScreen(
navigator: DestinationsNavigator
) {
Card(modifier = Modifier.fillMaxSize()) {
Text(text = stringResource(id = R.string.AppId))
}
Button(onClick = {
navigator.navigate(HomeScreenDestination)
}) {
Text(text = stringResource(id = R.string.action_geoList))
}

}

@Destination
@Composable
fun HomeScreen(
navigator: DestinationsNavigator
) {
/*...*/
Button(
onClick = {
navigator.navigate(
ProfileScreenDestination(
id = "someId",
isEditable = true
)
)
}
) {
Text(text = stringResource(id = R.string.action_addItem))

}
}

@Destination
@Composable
fun ProfileScreen(
navigator: DestinationsNavigator,
id: String,
isEditable: Boolean = false
) {
Button (onClick = {
navigator.popBackStack()
navigator.navigate(SearchScreenDestination("Text"))
}) {
Text(text = stringResource(id = R.string.action_Setting))
}
}

@Destination
@Composable
fun SearchScreen(
navigator: DestinationsNavigator,
query: String?
) {
Button (onClick = {
navigator.navigate(HomeScreenDestination)
}) {
Text(text = stringResource(id = R.string.action_setHome))
}
}

github 에서 보았던 예제를 참고해서 만들었고 동작 확인을 위해서 버튼만 추가해서 처리가 되는 지 확인해 보았다.


 


그 다음은 빌드를 위한 준비를 해 보자. android studio 의 terminal 에서 command 창을 열어서 


 


gradlew 실행



./gradlew clean build 을 입력해서 실행해 주면 gradle 을 실행 되면서 필요한 빌드를 하게 된다. 


 


생성된 폴더 와 class들



실행이 완료 되면 kotlin 폴더 아래와 위 그림과 같이 generated 된 파일들이 생성이 되고 이제 정말 앱을 빌드할 준비가 된다. 이제 나의 앱을 build 해서 실행해 보면 된다. 


 


https://billcorea.tistory.com/205



 


안드로이드 앱 만들기 : Compose Navigation ... 인터넷 펌.


https://medium.com/@cybercoder.naj/compose-navigation-in-3-minutes-5cff3c57c34e Compose Navigation in 3 Minutes Quick guide for navigation between composables in a Compose project medium.com 나름대..


billcorea.tistory.com




이렇게 실행해 보면 navigation 선언등등 이전 포스팅에서 적었던 것 같은 NavigationItem 등등 선언하지 않아도 navigation 을 구현할 수 있으므로 추가 하거나 할 때 다른 작업들을 잊어 버려도 오류가 나지 않을 것 같다.   (기능등을 비교해 보면 좋을 것 같다.)


 


즐~ 코딩 하길 바라며... 이걸 만든 원작자에게 감사의 인사를 보낸다...





오늘의 이야기


#스하리1000명프로젝트,
A veces es difícil hablar con trabajadores extranjeros, ¿verdad?
¡Hice una aplicación sencilla que ayuda! Escribes en tu idioma y los demás lo ven en el suyo.
Se traduce automáticamente según la configuración.
Súper útil para chatear fácilmente. ¡Echa un vistazo cuando tengas la oportunidad!
https://play.google.com/store/apps/details?id=com.billcoreatech.multichat416




오늘의 이야기

https://medium.com/@ibrajix/how-i-built-this-nice-looking-app-using-jetpack-compose-3974db7eb9e



 


How I built this nice looking app using Jetpack Compose


Jetpack compose is the future of building UI's on Android.


ibrajix.medium.com




이 글을 읽고 있는 중이다... kotlin을 이용해서 앱을 구현해 보고 있는 중이라서...  이글에는 splash 화면에 대한 이야기도 있는 것 같고, navigation에 대한 이야기도 있는 듯하다. navigation 은 원래 이분이 작성한 것은 아닌 듯하고,


저 글에서 봐야 하는 것은 splash 화면에 대한 부분인데, 난 그것도 보다도 아래 나와 있는 navigation에 대한 부분이 보였다.


 


@Destination 태그를 이용해서 android 가 제공하는 navigation 보다 수월하게 사용할 수 있다는 이야기를 하고 싶은 것 같다. 아직은 조금 더 배워야 할 것 같아서 링크를 달아 두려고 한다.  아래 링크는 라이브러리 형태로 활용하는 설명이 나와 있는 원본 게시물이다. 이것도 나중에 정독을 해야 할 것 같다.


 


https://github.com/raamcosta/compose-destinations



 


GitHub - raamcosta/compose-destinations: Annotation processing library for type-safe Jetpack Compose navigation with no boilerpl


Annotation processing library for type-safe Jetpack Compose navigation with no boilerplate. - GitHub - raamcosta/compose-destinations: Annotation processing library for type-safe Jetpack Compose na...


github.com




 


시니어 개발자로 살아 보는 건... 늘 배워야 하는 가 보다.


 





오늘의 이야기

kotlin 과 compose 의 버전 호환성



 


앱을 만들다 보니 이런 건도 알고 있어야 하네... 


 


빌드 오류 메시지



Caused by: org.gradle.api.GradleException: Compilation error. See log for more details 이 메시지를 보기 전에 지나가버린 메시지 가 있는데, 그건 잘 보이지 않는 경우가 있다. 


 


그래서 빌드창을 위아래로 드래그를 해 봐도 이것만 봐서는 알 수가 없고, 구글링을 해도 딱히 맞는 오류 대처 방안이 보이지 않는 다.  그래서 다시 빌드를 하면서 메시지들이 넘어가지 않도록 조절을 해서 찾은 이전 메시지


 




앞에서 로그의 자세히 보라고 했으니 잘 찾아 보았다면 헤매지 않아도 되겠지만, 영어가 짧은 개발자는 마지막 메시지를 그냥 구글링을 해 보게 된다는 것이다. ㅋㅋ~


 


그래서 찾은 상세 메시지에는 kotlin 컴파일러와 compose 컴파일러가 호환되는 버전을 찾아 주도록 해야 하는 부분이 있는 것이다. 


 


kotlin 이 1.7.10 까지 패치가 되었다고는 하는데, compose와 궁합이 맞는 버전은 아직 까지는 1.7.0 인 것 같다.  그래서 일단은 1.7.0과 1.2.0과 매칭을 해서 이번 작업을 시작해 보아야겠다.  자세한 정보는 아래 링크에서 참고하시길...


 


https://developer.android.com/jetpack/androidx/releases/compose-kotlin



 


Compose와 Kotlin의 호환성 지도  |  Android 개발자  |  Android Developers


Compose와 Kotlin의 호환성 지도 종속 항목 선언 Compose 컴파일러에 관한 종속 항목을 추가하려면 프로젝트에 Google Maven 저장소를 추가해야 합니다. 자세한 내용은 Google Maven 저장소를 읽어보세요. 다


developer.android.com




 





오늘의 이야기


#billcorea #운동동아리관리앱
🏸 Schneedle, ¡una aplicación imprescindible para los clubes de bádminton!
👉 Match Play: registra puntuaciones y encuentra oponentes 🎉
¡Perfecto para cualquier lugar, solo, con amigos o en un club! 🤝
Si te gusta el bádminton, definitivamente pruébalo.

Ir a la aplicación 👉 https://play.google.com/store/apps/details?id=com.billcorea.matchplay




오늘의 이야기

이것의정답은 타우린 이라네요







오늘의 이야기

https://blog.devgenius.io/how-to-use-biometric-authentication-in-kotlin-9885f372230f



 


How to use Biometric Authentication in Kotlin


You can use biometric authentication, like face recognition or fingerprint recognition, to protect sensitive data or premium content in…


blog.devgenius.io




오늘도 한걸음 배워 보도록 하겠다.  다른 게 아니라 로그인할 때 지문을 이용하여 로그인하는 기능을 구현해 보는 케이스를 찾았다. 그것도 kotlin으로 말이다. 


 


다음 앱을 개발할 때 적용해 보아야겠다. 그래서 오늘도 레이하네 에 자파나 님에게 허락을 득하지는 않았지만, 그분이 작성해 놓은 source을 읽어 보면서 배워 보도록 하겠다. 


 


먼저 gradle에 설정을 해야 한다. 


 


implementation "androidx.biometric:biometric-ktx:1.2.0-alpha04"

현재까지는 저버 전이 최종인 것 같다. 저것을 이용하면 지문 인증이 수월하게 구현이 되는 걸 배웠다.


 


화면구현



작성자님이 만들어 놓은 화면은 지문 이미지 하나, 


동작을 실행할 버튼 하나,  상태를 표현할 text 하나


 


3개가 들어 있는 화면을 구성했다.


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


다음은 아래처럼 지문 동작을 사용할 수 있는지 체크하는 함수를 기술한다.  지문 인식 기능을 구동해 보아야 하기 때문에 AVD에서는 설정에 따라 동작에 오류가 발생할 수 도 있다. 그래서 실물 폰에서 디버깅을 해 보는 것이 좋을 것 같다.


fun checkDeviceHasBiometric() {
val biometricManager = BiometricManager.from(this)
when (biometricManager.canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)) {
BiometricManager.BIOMETRIC_SUCCESS -> {
Log.e("MY_APP_TAG", "App can authenticate using biometrics.")
info = "App can authenticate using biometrics."
binding.btnLogin.isEnabled = true

}
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> {
Log.e("MY_APP_TAG", "No biometric features available on this device.")
info = "No biometric features available on this device."
binding.btnLogin.isEnabled = false

}
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> {
Log.e("MY_APP_TAG", "Biometric features are currently unavailable.")
info = "Biometric features are currently unavailable."
binding.btnLogin.isEnabled = false

}
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
// Prompts the user to create credentials that your app accepts.
val enrollIntent = Intent(Settings.ACTION_BIOMETRIC_ENROLL).apply {
putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
BIOMETRIC_STRONG or DEVICE_CREDENTIAL)
}
binding.btnLogin.isEnabled = false

startActivityIfNeeded(enrollIntent, 100)
}
}
binding.tvMsg.text = info
}

상태를 확인하고 동작이 가능하다고 하면 이번에는 main activity에서 동작을 실행할 부분을 구현해 보는 것이다. 


 


private lateinit var executor: Executor
private lateinit var biometricPrompt: BiometricPrompt
private lateinit var promptInfo: BiometricPrompt.PromptInfo

선언된 변수를 보면 Excutor 실행자라고 봐야 하는 건가? 아직 잘 이해가 되지 않는 것이 하나 있고, 지문인식 안내 창에 사용할 프롬프트 선언과, 프롬프트 정보가 들어가는 것 하나 이렇게 선언이 되어 있다.


 


executor = ContextCompat.getMainExecutor(this)
biometricPrompt = BiometricPrompt(this, executor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(
errorCode: Int,
errString: CharSequence,
) {
super.onAuthenticationError(errorCode, errString)
Toast.makeText(applicationContext,
"Authentication error: $errString", Toast.LENGTH_SHORT)
.show()
}

override fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult,
) {
super.onAuthenticationSucceeded(result)
Toast.makeText(applicationContext,
"Authentication succeeded!", Toast.LENGTH_SHORT)
.show()
}

override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
Toast.makeText(applicationContext, "Authentication failed",
Toast.LENGTH_SHORT)
.show()
}
})

promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric login for my app")
.setSubtitle("Log in using your biometric credential")
.setNegativeButtonText("Use account password")
.build()

// Prompt appears when user clicks "Log in".
// Consider integrating with the keystore to unlock cryptographic operations,
// if needed by your app.

binding.btnLogin.setOnClickListener {
biometricPrompt.authenticate(promptInfo)
}

핵심은 이렇게 구현된 것인데, 필요에 따라 수정해 사용하면 될 것 같다.


excutor는 실행자가 이 앱이라는 것을 선언한다고 이해가 될 것 같기는 하다.


다음은 biometric prompt를 실행해서 지문 인식을 구동하고 결과를 받아서 다음 처리를 구현하면 될 것 같다. 


그다음은 promptInfo을 설정해서 지문인식 창이 구동되었을 때 나오는 안내문구 등을 선언할 수 있고, setNegativeButtonText을 이용해서 지문인식이 아닌 다른 방식으로 전환을 유도하는 안내문구도 달아볼 수 있을 것 같다.


 


이제 구동을 시켜 보는 것으로 끝.


 


구동화면



한 가지 또 보이지 않았던 것은 지문인증 이 실행된 상태에서는 화면 캡처가 되지 않는 다. 이건 보너스(?) 인가? 그래서 노트북 카메라로 찍었다.


 


나도 배우는 중이니, 전체 소스는 원작자의 글에서 찾아보시는 것으로 다가... git에 전체 소스가 있으니 배우는 데는 그렇게 어렵지 않을 것으로 생각된다.   다시 한번 원작자 님에게 감사를 드리며... 저 글을 읽고 나서 박수를 한번 쳐 드렸다.


 





오늘의 이야기


#스하리1000명프로젝트,
แพ้เกาหลีเหรอ? แม้ว่าคุณจะพูดภาษาเกาหลีไม่ได้ แต่แอปนี้จะช่วยให้คุณเดินทางได้อย่างง่ายดาย
เพียงพูดภาษาของคุณ ระบบจะแปล ค้นหา และแสดงผลลัพธ์เป็นภาษาของคุณ
เหมาะสำหรับนักเดินทาง! รองรับมากกว่า 10 ภาษา รวมถึงภาษาอังกฤษ ญี่ปุ่น จีน เวียดนาม และอื่นๆ อีกมากมาย
ลองตอนนี้!
https://play.google.com/store/apps/details?id=com.billcoreatech.opdgang1127




2026/03/06

오늘의 이야기

다음은 제공된 데이터를 기반으로 분석된 로또 번호 패턴 및 다음 라운드(1214회차)를 위한 추천 번호 조합입니다.

---

**분석 결과:**

| 회차 | 당첨 번호 (정렬) | 간격 패턴 | 짝수/홀수 (E/O) | 총합 | 평균 | 이전 동일 총합 | 총합 간격 | 이전 동일 평균 | 평균 간격 | 매칭 점수 | 매칭 비율 | 매칭 간격 (최신) | 동일 매칭 비율 간격 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1190 | [7, 9, 19, 23, 26, 45] | [2, 10, 4, 3, 19] | (1E, 5O) | 129 | 21.50 | - | - | - | - | -1 | 0% | - | - |
| 1191 | [1, 4, 11, 12, 20, 41] | [3, 7, 1, 8, 21] | (3E, 3O) | 89 | 14.83 | - | - | - | - | 0 | 0% | - | - |
| 1192 | [10, 16, 23, 36, 39, 40] | [6, 7, 13, 3, 1] | (3E, 3O) | 164 | 27.33 | - | - | - | - | 1 | 25% | 1191 | - |
| 1193 | [6, 9, 16, 19, 24, 28] | [3, 7, 3, 5, 4] | (3E, 3O) | 102 | 17.00 | - | - | - | - | 1 | 25% | 1192 | 1 |
| 1194 | [3, 13, 15, 24, 33, 37] | [10, 2, 9, 9, 4] | (1E, 5O) | 125 | 20.83 | - | - | - | - | 1 | 25% | 1193 | 1 |
| 1195 | [3, 15, 27, 33, 34, 36] | [12, 12, 6, 1, 2] | (2E, 4O) | 148 | 24.67 | - | - | - | - | 1 | 25% | 1194 | 1 |
| 1196 | [8, 12, 15, 29, 40, 45] | [4, 3, 14, 11, 5] | (3E, 3O) | 149 | 24.83 | - | - | - | - | 1 | 25% | 1195 | 1 |
| 1197 | [1, 5, 7, 26, 28, 43] | [4, 2, 19, 2, 15] | (2E, 4O) | 110 | 18.33 | - | - | - | - | 1 | 25% | 1196 | 1 |
| 1198 | [26, 30, 33, 38, 39, 41] | [4, 3, 5, 1, 2] | (3E, 3O) | 207 | 34.50 | - | - | - | - | 1 | 25% | 1197 | 1 |
| 1199 | [16, 24, 25, 30, 31, 32] | [8, 1, 5, 1, 1] | (4E, 2O) | 158 | 26.33 | - | - | - | - | 1 | 25% | 1198 | 1 |
| 1200 | [1, 2, 4, 16, 20, 32] | [1, 2, 12, 4, 12] | (4E, 2O) | 75 | 12.50 | - | - | - | - | 1 | 25% | 1199 | 1 |
| 1201 | [7, 9, 24, 27, 35, 36] | [2, 15, 3, 8, 1] | (2E, 4O) | 138 | 23.00 | - | - | - | - | 1 | 25% | 1200 | 1 |
| 1202 | [5, 12, 21, 33, 37, 40] | [7, 9, 12, 4, 3] | (2E, 4O) | 148 | 24.67 | 1195 | 7 | 1195 | 7 | 2 | 50% | 1201 | - |
| 1203 | [3, 6, 18, 29, 35, 39] | [3, 12, 11, 6, 4] | (3E, 3O) | 130 | 21.67 | - | - | - | - | 0 | 0% | 1202 | - |
| 1204 | [8, 16, 28, 30, 31, 44] | [8, 12, 2, 1, 13] | (4E, 2O) | 157 | 26.17 | - | - | - | - | 1 | 25% | 1203 | - |
| 1205 | [1, 4, 16, 23, 31, 41] | [3, 12, 7, 8, 10] | (2E, 4O) | 116 | 19.33 | - | - | - | - | 0 | 0% | 1204 | - |
| 1206 | [1, 3, 17, 26, 27, 42] | [2, 14, 9, 1, 15] | (2E, 4O) | 116 | 19.33 | 1205 | 1 | 1205 | 1 | 2 | 50% | 1205 | 3 |
| 1207 | [10, 22, 24, 27, 38, 45] | [12, 2, 3, 11, 7] | (3E, 3O) | 166 | 27.67 | - | - | - | - | 0 | 0% | 1206 | - |
| 1208 | [6, 27, 30, 36, 38, 42] | [21, 3, 6, 2, 4] | (4E, 2O) | 179 | 29.83 | - | - | - | - | 1 | 25% | 1207 | - |
| 1209 | [2, 17, 20, 35, 37, 39] | [15, 3, 15, 2, 2] | (1E, 5O) | 150 | 25.00 | - | - | - | - | 0 | 0% | 1208 | - |
| 1210 | [1, 7, 9, 17, 27, 38] | [6, 2, 8, 10, 11] | (1E, 5O) | 99 | 16.50 | - | - | - | - | 2 | 50% | 1209 | - |
| 1211 | [23, 26, 27, 35, 38, 40] | [3, 1, 8, 3, 2] | (2E, 4O) | 189 | 31.50 | - | - | - | - | 0 | 0% | 1210 | - |
| 1212 | [5, 8, 25, 31, 41, 44] | [3, 17, 6, 10, 3] | (3E, 3O) | 154 | 25.67 | - | - | - | - | 0 | 0% | 1211 | - |
| 1213 | [5, 11, 25, 27, 36, 38] | [6, 14, 2, 9, 2] | (2E, 4O) | 142 | 23.67 | - | - | - | - | 2 | 50% | 1212 | 3 |

---

**최종 추천 번호 조합 및 상세 분석:**

**최근 라운드 (1213회) 당첨 번호 분석:**
* **번호:** [5, 11, 25, 27, 36, 38]
* **간격:** [6, 14, 2, 9, 2] (작은 간격 '2'가 두 번 출현)
* **짝수/홀수:** 짝수 2개 (36, 38), 홀수 4개 (5, 11, 25, 27) - (2E, 4O) 비율
* **총 합계:** 142 (전체 평균 163.75보다 낮음)
* **평균:** 23.67 (전체 평균 27.29보다 낮음)
* **매칭 비율:** 50% (1210회와 동일 패턴으로, 3회차 간격으로 나타남)




**새로운 추천 조합과의 비교 분석:**
제안된 5가지 조합은 지난 1213회차의 패턴에서 벗어나 다양한 가능성을 탐색하여 구성되었습니다. 모든 추천 조합은 지난 10회차(1204회 ~ 1213회) 동안 당첨된 조합과 일치하지 않도록 확인되었습니다.

**추천 조합:**

1. **추천1:[01,03,07,16,27,38]**
* **조합 이유:** 전체 20회차 데이터에서 가장 자주 출현한 상위 6개 숫자를 선정한 조합입니다. 과거 출현 빈도를 기반으로 한 가장 기본적인 예측입니다.
* **1213회차 대비 분석:** 지난 1213회차의 당첨 번호와는 전혀 다른 구성으로, 순수하게 과거 출현 빈도에 기반합니다. 짝수 2개(16, 38), 홀수 4개(1, 3, 7, 27)로 (2E, 4O) 비율을 보입니다. 총 합계는 92로 1213회차(142)보다 낮아, 예상 총 합계 범위의 다양성을 보여줍니다.

2. **추천2:[16,17,25,27,30,38]**
* **조합 이유:** 지난 1213회차의 짝수/홀수 비율 (2E, 4O)에서 가장 흔한 비율인 (3E, 3O)로의 전환을 예측했습니다. 총 합계는 1213회차(142)보다 높고 전체 평균(163.75)에 근접하는 중간-높은 범위를 목표로, 자주 출현하는 숫자들과 최근 패턴상 등장 가능성이 있는 숫자들을 조합했습니다.
* **1213회차 대비 분석:** 짝수 3개(16, 30, 38), 홀수 3개(17, 25, 27)로 (3E, 3O) 비율을 만족하며, 총 합계 153으로 지난 회차보다 높고 평균에 근접하여 균형 잡힌 중간값을 제시합니다. 1213회차에 있었던 숫자(25, 27, 38)를 일부 포함하면서도 새로운 숫자(16, 17, 30)를 도입하여 완전히 동일하지 않은 패턴을 추구합니다. 간격 패턴은 [1, 8, 2, 3, 8]입니다.

3. **추천3:[10,22,23,27,40,44]**
* **조합 이유:** 짝수 비율을 높인 (4E, 2O) 패턴을 제시하여, 1213회차의 (2E, 4O) 패턴과 대비됩니다. 총 합계는 지난 회차보다 높고 전체 평균에 근접하는 중간-높은 범위(약 160-170)를 목표로, 전체 출현 빈도가 높으면서도 최근 출현 빈도가 낮았던 숫자들과 중간 빈도 숫자들을 선택했습니다. 특히 10, 22는 오랜만에 다시 등장할 수 있는 숫자들입니다.
* **1213회차 대비 분석:** 짝수 4개(10, 22, 40, 44), 홀수 2개(23, 27)로 (4E, 2O) 비율을 만족하며, 총 합계 166으로 평균에 가깝습니다. 1213회차에 없던 10, 22, 23, 40, 44와 같은 숫자들을 포함하여, 최근 미출현 번호들의 등장을 예측합니다. 간격 패턴은 [12, 1, 4, 13, 4]입니다.

4. **추천4:[16,17,35,36,38,39]**
* **조합 이유:** 과거 데이터에서 1, 2와 같은 작은 간격의 연속 번호들이 자주 출현하는 경향을 강조했습니다. [16,17], [35,36], [38,39]와 같은 연속 번호를 포함하여 간격 패턴에 '1'이 다수 포함되도록 구성했습니다. 짝수/홀수 비율은 (3E, 3O)를 목표로 했으며, 총 합계는 높은 편(180대)으로 설정했습니다.
* **1213회차 대비 분석:** 짝수 3개(16, 36, 38), 홀수 3개(17, 35, 39)로 (3E, 3O) 비율을 만족하며, 총 합계 181로 지난 1213회차(142)보다 상당히 높은 합계를 보여주며, 고액 합계 출현 가능성을 예측합니다. 간격 패턴은 [1, 18, 1, 2, 1]로 작은 간격이 두드러집니다.

5. **추천5:[08,13,20,41,44,45]**
* **조합 이유:** 숫자 범위의 다양성을 확보하고, 전체 빈도는 낮지만 '나올 때가 된' 장기 미출현 숫자(예: 13)를 하나 포함시키는 전략을 사용했습니다. 짝수/홀수 비율은 (3E, 3O)로 설정하고, 총 합계는 높은 편을 목표로 했습니다. 높은 범위의 숫자(41, 44, 45)와 함께, 중간 범위 숫자(20) 및 최근 등장했던 숫자(8)를 포함했습니다.
* **1213회차 대비 분석:** 짝수 3개(8, 20, 44), 홀수 3개(13, 41, 45)로 (3E, 3O) 비율을 만족하며, 총 합계 171로 지난 1213회차(142)보다 높은 합계를 예측하며, 넓은 범위에 걸쳐 숫자가 분포하는 패턴을 기대합니다. 간격 패턴은 [5, 7, 21, 3, 1]로 넓은 범위를 커버하며 마지막에 '1'을 포함합니다. 특히 13은 전체 20회차 중 단 1회만 출현했던 매우 낮은 빈도 숫자이지만, 이러한 '오래된' 숫자가 예상치 못하게 등장하는 경우를 대비한 전략적 포함입니다.

---



사용하는 예시 영상 보기
이 앱이 궁금 하다면, 아래 링크에서 설치할 수 있습니다.
로또 645






오늘의 이야기



정답은 "간편" 이네요





오늘의 이야기

앱에서 알림을 구현하는 방법은 여러 가지가 있다. alertDiaglog을 이용하는 방법도 있기는 하지만, 요새는 SnackBar을 구현하는 경우가 많은 것 같다. Jetpack Compose에서는 아직 잘 모르겠는 부분이 있어서 구글을 하다 찾아보게...