I'm creating an Android Library for basic dialogs. Right now, all I have is a basic-dialogs module along with the app module. I'm calling a composable in the basic-dialogs module from the Activity in the app module, and I keep getting the exception error message below about a No static method when I try to run the app. What could be wrong with the code?
java.lang.NoSuchMethodError: No static method BasicDialog(Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V in class Lcom/<domain>/basic_dialogs/BasicDialogKt; or its super classes (declaration of 'com.<domain>.basic_dialogs.BasicDialogKt' appears in /data/app/~~DOqVbMGsnzDWFS7_YdNgtw==/com.<domain>.composedialogs-_5IuirMOFh5F8pL884Urnw==/base.apk!classes2.dex)
Activity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeDialogsTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
BasicDialog(onDismiss = { }, onConfirmClick = { }, title = "Test Dialog", confirmButtonText = "Open") {
Text("This is a test dialog.")
}
}
}
}
}
}
BasicDialog Composable
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun BasicDialog(
title: String = "",
confirmButtonText: String,
onDismiss: () -> Unit,
onConfirmClick: () -> Unit,
content: @Composable () -> Unit
) {
Surface(
shape = MaterialTheme.shapes.medium,
color = MaterialTheme.colors.surface,
modifier = Modifier
.padding(4.dp)
) {
Dialog(
onDismissRequest = onDismiss,
properties = DialogProperties(
dismissOnBackPress = true,
dismissOnClickOutside = true,
usePlatformDefaultWidth = false
),
) {
if (title != "") {
Text(title)
Spacer(Modifier.padding(5.dp))
}
content()
Spacer(Modifier.padding(5.dp))
TextButton(onClick = onDismiss) {
Text(text = stringResource(id = R.string.dialog_cancel), fontSize = 16.sp)
}
TextButton(onClick = { onConfirmClick() }) {
Text(text = confirmButtonText, fontSize = 16.sp)
}
}
}
}
Project Gradle file
buildscript {
ext {
compose_version = '1.1.0-beta01'
}
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.2.2' apply false
id 'com.android.library' version '7.2.2' apply false
id 'org.jetbrains.kotlin.android' version '1.5.31' apply false
}
task clean(type: Delete) {
delete rootProject.buildDir
}
app module Gradle file
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.<domain>.composedialogs"
minSdk 27
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.activity:activity-compose:1.3.1'
implementation project(path: ':basic-dialogs')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
basic-dialog module Grade file
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdk 32
defaultConfig {
minSdk 27
targetSdk 32
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
}
The following needs to be added to the basic-dialogs module's build.gradle file:
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
}
Entire Gradle file
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdk 32
defaultConfig {
minSdk 27
targetSdk 32
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
}
}
dependencies {
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
}
Let me hopefully save someone the 3 hours this just cost me. If you are using the Compose BOM in a multi-module project and need an updated version of an individual dependency different to what is specified in the BOM, and your modules also share the BOM, then be very careful sharing dependencies across modules.
In my example I had:
implementation(platform(libs.androidx.compose.bom))
api("androidx.compose.material3:material3:1.1.0-rc01") // Relatively new and needed for date & time pickers
in one module, then a load of other modules depending on this one. Some of those modules also specified:
implementation(libs.androidx.compose.material3)
This caused havoc with the app, where one module was perfectly fine and other unrelated ones were crashing at runtime telling me they didn't know what a TextField was.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With