androidkotlinandroid-jetpack-composeandroid-jetpack

NoSuchMethodException for straight-forward ViewModel in Jetpack Compose setup


The setup below seems straight-forward (to me) but fails with FATAL EXCEPTION: main due to java.lang.NoSuchMethodException: com.mydummy.viewmodeltesting.DummyViewModel.<init> [].

That's interesting. The init() method is there. I also tested this with a completely new EmptyActivity project in Android Studio, which has the following setup.

MainActivity.kt

class MainActivity : ComponentActivity() {
    val viewModel: DummyViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ViewModelTestingTheme {
                val data by viewModel.dataState.collectAsState()
                Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
                    ShowDataList(dataList = data)
                }
            }
        }
    }
}

@Composable
fun ShowDataList(dataList: List<DummyMetadata>, modifier: Modifier = Modifier) {
    Box(modifier = Modifier.fillMaxSize()) {
        LazyColumn(modifier = Modifier) {
            items(dataList) { data -> ShowDataItem(model = data)}
        }
    }
}

@Composable
fun ShowDataItem(model: DummyMetadata) {
    Card(shape = RoundedCornerShape(8.dp), modifier = Modifier) {
        Text(text = model.title)
    }
}

DummyViewModel.kt

class DummyViewModel(private val _repository: DummyRepository): ViewModel() {
    private val _dataState = MutableStateFlow<List<DummyMetadata>>(emptyList())
    val dataState: StateFlow<List<DummyMetadata>> = _dataState

    init {
        fetchData()
    }

    private fun fetchData() {
        viewModelScope.launch {
            try {
                val data = _repository.collectDummyData()
                _dataState.value = data
            } catch (e: Exception) {
                // TODO Error handling or at least better logging
                e.printStackTrace()
            }
        }
    }
}

DummyRepository.kt

class DummyRepository {
    suspend fun collectDummyData(): List<DummyMetadata> {
        return listOf(
            DummyMetadata("First dummy"),
            DummyMetadata("Second dummy"),
            DummyMetadata("Last dummy")
        )
    }
}

And the data class in DummyMetadata.kt is:

data class DummyMetadata(
    val title: String
)

That's all. The ViewModel class and the associated Repository & data model look fine. Don't they?


Solution

  • java.lang.NoSuchMethodException: com.mydummy.viewmodeltesting.DummyViewModel.<init> []. It means that there isn't a no-argument constructor available. by viewModels() seems not to be able to create this view model instance without a custom factory