I'm new in Kotlin and I'm facing problem with DataBinding - Cannot access class ViewModel. Check your module classpath for missing or conflicting dependencies. But DataBinding is connect in block buildFeatures
My build.gradle.kts(androidApp):
plugins {
id("com.android.application")
kotlin("android")
id("kotlin-android")
id("com.squareup.sqldelight")
id("kotlinx-serialization")
id("kotlin-kapt")
}
android {
compileSdkVersion(30)
defaultConfig {
applicationId = "com.rompos.activator.kmm.androidApp"
minSdkVersion(26)
targetSdkVersion(30)
versionCode = 1
versionName = "1.0"
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
buildFeatures {
viewBinding = true
dataBinding = true
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
packagingOptions {
pickFirst("META-INF/*.kotlin_module")
}
kapt {
generateStubs = true
correctErrorTypes = true
}
}
dependencies {
implementation(project(":shared"))
implementation("com.google.android.material:material:1.2.1")
implementation("androidx.core:core-ktx:1.3.2")
implementation("androidx.appcompat:appcompat:1.2.0")
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.recyclerview:recyclerview:1.1.0")
implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("androidx.activity:activity-ktx:1.1.0")
implementation("androidx.fragment:fragment-ktx:1.2.5")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.2.0")
implementation("androidx.lifecycle:lifecycle-common-java8:2.2.0")
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.2.0")
implementation("com.squareup.sqldelight:android-driver:1.4.4")
implementation("org.kodein.di:kodein-di:7.1.0")
}
Fragment where I got error:
const val EDIT_MODEL = "editModel"
const val EDIT_MODEL_ID = "editModelId"
open class EditServerFragment : Fragment() {
private var _viewBinding: FragmentEditServerBinding? = null
private val viewBinding get() = _viewBinding!!
private val repository: ServersRepository by myApp.kodein.instance()
private var serverFormViewModel = ServerFormViewModel()
private var serverId: Long = 0
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_viewBinding = FragmentEditServerBinding.inflate(inflater, container, false)
val view = viewBinding.root
val binding : FragmentEditServerBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_edit_server, container, false)
(Error here ->)**binding.item** = serverFormViewModel
// Dispatcher Back Step to Main
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
toMain()
}
})
if (arguments?.getLong("ID") != null) {
serverId = arguments?.getLong("ID")!!
}
// Set title
if (activity is AppCompatActivity) {
(activity as AppCompatActivity).supportActionBar?.title = getString(R.string.edit_server)
}
if (serverId > 0) {
lifecycleScope.launch {
viewBinding.progressBar.visibility = View.VISIBLE
repository.get(serverId).let { server ->
serverFormViewModel.setForm(server)
}
}.also {
viewBinding.progressBar.visibility = View.GONE
}
}
(Error here ->)**binding.item** = serverFormViewModel
viewBinding.cancelBtn.setOnClickListener {
toMain()
}
viewBinding.saveBtn.setOnClickListener {
if (serverFormViewModel.isFormValid()) {
lifecycleScope.launch {
saveRecord(serverFormViewModel)
requireActivity().run {
startActivity(Intent(this, MainActivity::class.java))
finish()
}
}.also {
toMain()
}
} else {
Utils.snackMsg(view, getString(R.string.error_empty_field))
println("EMPTY")
}
}
return viewBinding.root
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putLong(EDIT_MODEL_ID, serverId)
outState.putParcelable(EDIT_MODEL, serverFormViewModel.getModel())
}
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
if (savedInstanceState != null) {
serverId = savedInstanceState.getLong(EDIT_MODEL_ID)
serverFormViewModel.setForm(savedInstanceState.getParcelable(EDIT_MODEL)!!)
}
}
private fun saveRecord(viewModel: ServerFormViewModel) {
viewBinding.progressBar.visibility = View.VISIBLE
try {
repository.save(serverId, viewModel.getModel(serverId))
toMain()
} catch (e: Exception) {
view?.let { Utils.snackMsg(it, e.message.toString()) }
} finally {
viewBinding.progressBar.visibility = View.GONE
}
}
private fun toMain() {
requireActivity().run {
startActivity(Intent(this, MainActivity::class.java))
finish()
}
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="item"
type="com.rompos.activator.kmm.shared.model.ServerFormViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/editView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/server_title"
app:endIconMode="clear_text"
tools:layout_editor_absoluteY="8dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/serverTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="@={item.title}" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/server_url"
app:endIconMode="clear_text">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/serverUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textUri"
android:singleLine="true"
android:text="@={item.url}" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/server_token"
app:endIconMode="clear_text">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/serverToken"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="@={item.token}" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center|bottom"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="@+id/cancelBtn"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel_btn"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/saveBtn"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/saveBtn"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/save_btn"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#68898989"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ProgressBar
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTintMode="add"
android:progressBackgroundTintMode="multiply"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
ViewModel:
class ServerFormViewModel {
private var serverModel = ServerViewModel()
fun setForm(server: Server) {
serverModel.setModel(server)
}
fun setForm(viewModel: ServerViewModel) {
serverModel = viewModel
}
fun getTitle() : String {
return serverModel.title ?: ""
}
fun setTitle(value: String) {
serverModel.title = value
}
fun getUrl() : String {
return serverModel.url ?: ""
}
fun setUrl(value: String) {
serverModel.url = value
}
fun getToken() : String {
return serverModel.token ?: ""
}
fun setToken(value: String) {
serverModel.token = value
}
fun isFormValid() : Boolean {
return !serverModel.title.isNullOrEmpty() and !serverModel.url.isNullOrEmpty() and !serverModel.token.isNullOrEmpty()
}
fun getModel(id: Long?) : Server {
return Server(id!!, serverModel.title, serverModel.url, serverModel.token)
}
fun getModel() : ServerViewModel {
return serverModel
}
}
This proj on Git: https://github.com/Diy2210/com.rompos.activator.kmm
I think you need to bind your ViewModel just in
onViewCreated
method.