【问题标题】:Android Studio Room data without livedata没有 livedata 的 Android Studio Room 数据
【发布时间】:2021-04-13 23:34:40
【问题描述】:

我得到了以下 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>

Name.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
}

NameDatabase.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-studio kotlin android-room data-persistence


    【解决方案1】:

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

    可能的解决方案如下。

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

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

    【讨论】:

    • 感谢您的回答。你知道在我的情况下我会怎么做吗?或者如果可能的话,你有什么例子吗?
    • Tyvm 更新,不幸的是我仍然不明白我的错误到底在哪里。从您的第一点和第二点开始,我不明白为什么我必须让我的 dao 和方法采用随机数,因为我已经有了这个查询 @Query("SELECT name FROM name_data ORDER BY RANDOM() LIMIT 1") 来为我做这件事。然后我开始尝试至少你的第 3 点和第 4 点,并尝试从我的视图级别启动协程,如下所示:lifecycleScope.launch(Dispatchers.IO) 但不幸的是,这再次给了我一个 Unit 类型作为结果并使用 toString() 方法输出错误的名称
    • 啊,很抱歉没有注意到您已经实现了某种随机逻辑。好的,所以您唯一需要做的就是确保 getRandomName 内部视图模型通过使其暂停返回一些值
    • 我暂停了 viewmodel 方法,但由于某种原因,我仍然没有得到想要的输出。该方法仍然不返回字符串,而是像在单元之前一样。有什么建议吗?
    • 你有这样的吗? suspend fun getRandomName() = repository.getRandomName()
    【解决方案2】:

    所以经过一些测试和反复测试,这就是我所拥有的,它似乎正在工作。 如果有人有一些东西要带进来,我很乐意接受,并非常感谢 georkost 提供所有有用的提示!

    // No changes made to database
    
    @Entity(tableName = "name_data")
    data class Name (
        @PrimaryKey(autoGenerate = true) val id: Int,
        @ColumnInfo(name = "name") val name: String
    )
    
    //*********************************************************************************
    
    // Changed return type from Query to LiveData<String> (was just String before)
    
    @Dao
    interface NameDao {
    
        @Insert
        fun addName(name: Name)
    
        @Query("SELECT name FROM name_data ORDER BY RANDOM() LIMIT 1")
        fun getRandomName(): LiveData<String>    // HERE
    }
    
    //*********************************************************************************
    
    // Changed getRandomMeal from fun to val
    
    class NameRepository(private val nameDao: NameDao) {
    
         val getRandomMeal: LiveData<String> = nameDao.getRandomName()  // HERE
    
         fun addName(name: Name) { nameDao.addName(name) }
    }
    
    //*********************************************************************************
    
    // Added getRandomName val, initialized it and removed the fun
    
    class NameViewModel(application: Application): AndroidViewModel(application) {
    
        val getRandomName: LiveData<String>             // HERE
        private val repository: NameRepository
    
        init {
            val nameDao = NameDatabase.getDatabase(application).nameDao()
            repository = NameRepository(nameDao)
            getRandomName = repository.getRandomMeal    // HERE
        }
    
        fun addName(name: Name) {
            viewModelScope.launch(Dispatchers.IO){
                repository.addName(name)
            }
        }
    }
    
    //*********************************************************************************
    
    // Changed the last row to observe the LiveData and display it in the Text View
    
    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()
    
                // HERE
                mNameViewModel.getRandomName.observe(this, Observer { String -> tv.text = String })
    
    
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多