首页 > 解决方案 > 没有 livedata 的 Android Studio Room 数据

问题描述

我得到了以下 Room 数据库,并希望在文本视图中输出随机用户的名称。不幸的是,运行代码会产生输出:文本视图中的kotlin.unit。我的文件如下所示:

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var mNameViewModel: NameViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mNameViewModel = ViewModelProvider(this).get(NameViewModel::class.java)

        val btn = findViewById<Button>(R.id.btn_addName)
        val tv = findViewById<TextView>(R.id.tv_showName)

        btn.setOnClickListener {
            val text = findViewById<EditText>(R.id.et_enterName)?.text.toString()
            val name = Name(0, text)

            // Add Data to Database
            mNameViewModel.addName(name)
            Toast.makeText(applicationContext, "Successfully added $text.", Toast.LENGTH_LONG).show()

            val randomName = mNameViewModel.getRandomName()

            // Without .toString() I get an error, with it it displays kotlin.unit
            tv.text = randomName.toString() 
        }

    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_showName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.133" />

    <EditText
        android:id="@+id/et_enterName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="textPersonName"
        android:hint="Name"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.497"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.244" />

    <Button
        android:id="@+id/btn_addName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.379" />

</androidx.constraintlayout.widget.ConstraintLayout>

名称.kt

@Entity(tableName = "name_data")
data class Name (
    @PrimaryKey(autoGenerate = true) val id: Int,
    @ColumnInfo(name = "name") val name: String
)

NameDao.kt

@Dao
interface NameDao {

    @Insert
    fun addName(name: Name)

    @Query("SELECT name FROM name_data ORDER BY RANDOM() LIMIT 1")
    fun getRandomName(): String
}

名称数据库.kt

@Database(entities = [Name::class], version = 1, exportSchema = false)
abstract class NameDatabase: RoomDatabase() {

    abstract fun nameDao(): NameDao

    companion object{
        @Volatile
        private var INSTANCE: NameDatabase? = null

        fun getDatabase(context: Context): NameDatabase{
            val tempInstance = INSTANCE
            if(tempInstance != null){
                return tempInstance
            }
            synchronized(this){
                val instance = databaseBuilder(
                    context.applicationContext,
                    NameDatabase::class.java,
                    "name_data"
                ).build()
                INSTANCE = instance
                return instance
            }
        }
    }
}

NameRepository.kt

class NameRepository(private val nameDao: NameDao) {

     fun getRandomName() { nameDao.getRandomName() }

     fun addName(name: Name) { nameDao.addName(name) }
}

NameViewModel.kt

class NameViewModel(application: Application): AndroidViewModel(application) {

    private val repository: NameRepository

    init {
        val nameDao = NameDatabase.getDatabase(application).nameDao()
        repository = NameRepository(nameDao)
    }

    fun addName(name: Name) {
        viewModelScope.launch(Dispatchers.IO){
            repository.addName(name)
        }
    }

    fun getRandomName() {
        viewModelScope.launch(Dispatchers.IO){
            repository.getRandomName()
        }
    }
}

这是按下按钮时textview的输出方式。

按下按钮时的外观

数据库被填充了。

数据库被填充

感谢任何帮助以显示数据。谢谢!

标签: android-studiokotlinandroid-roomdata-persistence

解决方案


问题是,在getRandomNumberviewmodel 内部的方法中,您没有返回任何内容,这就是您得到kotlin.unit. 相反,您应该确保返回一个值

一个可能的解决方案如下。

  1. 在您的 dao 中创建一个方法,该方法接受一个数字并返回该行(这实际上是随机名称)
  2. 从您的 repo 调用该方法,您可以使用随机数Random.getNextInt不确定如何获得随机数
  3. 从您的视图模型调用该方法
  4. 从您的按钮 onClick 调用 viewModel 方法

确保suspend在适用的地方使用以获得结果。对于我上面展示的情况,将在视图级别启动协程并进行其余调用(vm、repo、dao)suspend


推荐阅读