Android Room数据库报2个Kapt编译错误 附完整代码求排查解决
运行报错信息
应用编译阶段触发kapt相关错误,错误日志如下:
C:\Users\John\AndroidStudioProjects\Todoit 2\app\build\tmp\kapt3\stubs\debug\com\example\todoit\data\TodoDao.java:11: error: Not sure how to handle insert method's return type. public abstract java.lang.Object addTodo(@org.jetbrains.annotations.NotNull() C:\Users\John\AndroidStudioProjects\Todoit 2\app\build\tmp\kapt3\stubs\debug\com\example\todoit\data\TodoDao.java:13: error: Type of the parameter must be a class annotated with @Entity or a collection/array of it. kotlin.coroutines.Continuation<? super kotlin.Unit> continuation);
问题根因
报错由两个问题共同导致:
- Room依赖版本不一致且版本过低:模块级Gradle文件中预先定义了
roomVersion = "2.4.2",但实际引入room-ktx和room-compiler时硬编码使用了2.2.1版本,该旧版本对Kotlin协程suspend关键字的kapt处理存在兼容缺陷,会将协程编译时自动生成的Continuation参数误判为DAO方法的业务入参,同时无法识别suspend修饰的插入方法返回类型,触发上述两个编译错误。 - 代码存在语法缺失:
MainActivity中btnAddTodo的点击监听闭包缺少闭合大括号,会额外触发语法编译错误。
修复方案
按以下步骤操作即可解决问题:
- 打开模块级
build.gradle文件,修改Room依赖项,统一使用已定义的版本变量,保证room-ktx与room-compiler版本完全一致:
//ROOM def roomVersion = "2.4.2" implementation "androidx.room:room-ktx:$roomVersion" kapt "androidx.room:room-compiler:$roomVersion"
- 打开
MainActivity.kt,补全btnAddTodo点击监听缺失的闭合大括号,修正后对应代码段如下:
btnAddTodo.setOnClickListener { val todoTitle = etTodoTitle.text.toString() if (todoTitle.isNotEmpty()) { val todo = Todo(0,todoTitle,false) etTodoTitle.text.clear() insertDataToDataBase(todo) todoAdapter.addTodo(todo) } } btnDeleteTodo.setOnClickListener { todoAdapter.deleteDoneTodos() }
- 依赖和代码修改完成后,依次点击菜单栏
File -> Invalidate Caches...清除缓存并重启Android Studio,重启后执行Build -> Clean Project、Build -> Rebuild Project重新编译项目即可。
附:问题相关项目代码
Todo实体类
package com.example.todoit.data import androidx.room.Entity import androidx.room.PrimaryKey @Entity(tableName = "todo_data") data class Todo ( @PrimaryKey val id: Int, val title: String, var isChecked: Boolean = false )
TodoDao
package com.example.todoit.data import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query @Dao interface TodoDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun addTodo(todo: Todo) @Query("SELECT * FROM todo_data ORDER BY id ASC") fun readAllData(): LiveData<List<Todo>> }
TodoDataBase
package com.example.todoit.data import android.content.Context import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase @Database(entities = [Todo::class],version = 1, exportSchema = false) abstract class TodoDataBase: RoomDatabase() { abstract fun todoDao(): TodoDao companion object{ @Volatile private var INSTANCE: TodoDataBase? = null fun getDataBase(context: Context):TodoDataBase{ val tempInstance = INSTANCE if(tempInstance != null){ return tempInstance } synchronized(this){ val instance = Room.databaseBuilder( context.applicationContext, TodoDataBase::class.java, "todo_database" ).build() INSTANCE = instance return instance } } } }
TodoRepository
package com.example.todoit.data import androidx.lifecycle.LiveData class TodoRepository(private val todoDao:TodoDao) { val readAllData: LiveData<List<Todo>> = todoDao.readAllData() suspend fun addTodo(todo:Todo) { todoDao.addTodo(todo) } }
TodoViewModel
package com.example.todoit.data import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class TodoViewModel(application: Application) : AndroidViewModel(application) { private val readAllData: LiveData<List<Todo>> private val repository: TodoRepository init { val todoDao = TodoDataBase.getDataBase(application).todoDao() repository = TodoRepository(todoDao) readAllData = repository.readAllData } fun addTodoToDataBase(todo: Todo) { viewModelScope.launch(Dispatchers.IO) { repository.addTodo(todo) } } }
修复前MainActivity
package com.example.todoit import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager import com.example.todoit.data.Todo import com.example.todoit.data.TodoViewModel import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { private lateinit var todoAdapter: TodoAdapter private lateinit var todoViewModel: TodoViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) todoViewModel = ViewModelProvider(this).get(TodoViewModel::class.java) todoAdapter = TodoAdapter(mutableListOf()) rvTodoItems.layoutManager = LinearLayoutManager(this) rvTodoItems.adapter = todoAdapter btnAddTodo.setOnClickListener { val todoTitle = etTodoTitle.text.toString() if (todoTitle.isNotEmpty()) { val todo = Todo(0,todoTitle,false) etTodoTitle.text.clear() insertDataToDataBase(todo) todoAdapter.addTodo(todo) } btnDeleteTodo.setOnClickListener { todoAdapter.deleteDoneTodos() } }} private fun insertDataToDataBase(todo: Todo) { val todoTitle = etTodoTitle.text.toString() if(todoTitle.isNotEmpty()) { //Add data to database todoViewModel.addTodoToDataBase(todo) } } }
TodoAdapter
package com.example.todoit import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.example.todoit.data.Todo import kotlinx.android.synthetic.main.item_todo.view.* class TodoAdapter( private val todos: MutableList<Todo>, ) : RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() { class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder { return TodoViewHolder( LayoutInflater.from(parent.context).inflate( R.layout.item_todo, parent, false ) ) } fun addTodo(todo: Todo) { todos.add(todo) notifyItemInserted(todos.size - 1) } fun deleteDoneTodos() { todos.removeAll { todo -> todo.isChecked } notifyDataSetChanged() } private fun toggleStrikeThrough(tvTodoTitle: TextView, isChecked: Boolean) { if (isChecked) { tvTodoTitle.paintFlags = tvTodoTitle.paintFlags or STRIKE_THRU_TEXT_FLAG } else { tvTodoTitle.paintFlags = tvTodoTitle.paintFlags and STRIKE_THRU_TEXT_FLAG.inv() } } override fun onBindViewHolder(holder: TodoViewHolder, position: Int) { val curTodo = todos[position] holder.itemView.apply { tvTodoTitle.text = curTodo.title cbDone.isChecked = curTodo.isChecked toggleStrikeThrough(tvTodoTitle, curTodo.isChecked) cbDone.setOnCheckedChangeListener { _, isChecked -> toggleStrikeThrough(tvTodoTitle, isChecked) curTodo.isChecked = !curTodo.isChecked } } } override fun getItemCount(): Int { return todos.size } }
修复前模块级Gradle配置
plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' id "kotlin-android-extensions" } apply plugin: 'kotlin-kapt' android { compileSdk 32 defaultConfig { applicationId "com.example.todoit" minSdk 21 targetSdk 32 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } 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 { //ROOM def roomVersion = "2.4.2" implementation 'androidx.room:room-ktx:2.2.1' kapt "androidx.room:room-compiler:2.2.1" // Navigation Component implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2' implementation 'androidx.navigation:navigation-ui-ktx:2.2.2' implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.6.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' // Lifecycle components implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" // Kotlin components implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72" api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5" api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5" }
项目级Gradle配置
// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id 'com.android.application' version '7.2.0' apply false id 'com.android.library' version '7.2.0' apply false id 'org.jetbrains.kotlin.android' version '1.5.30' apply false } task clean(type: Delete) { delete rootProject.buildDir }
内容的提问来源于stack exchange,提问作者Clivityy
相关产品推荐
相关产品推荐

