我正在尝试传递在活动(NewWordActivity.kt)中的两个 EditText 中输入的数据,并将其发送到 MainActivity 以显示它们,但每次我单击“保存”按钮时,它都会显示“Word not saved because it's Empty”以下代码包括房间设置代码和其他所需代码。
Word.kt
@Entity(tableName = "word_table")
class Word(
@PrimaryKey @ColumnInfo(name = "word") val word: String,
@ColumnInfo(name = "def") val def: String
)
WordDao.kt
@Dao
interface WordDao {
@Query("SELECT * FROM word_table ORDER BY word ASC")
fun getAlphabetizedWords(): Flow<List<Word>>
@Insert
suspend fun insertWord(word: Word)
}
WordRoomDatabase.kt
// Annotates class to be a Room Database with a table (entity) of the Word class
@Database(entities = [Word::class], version = 2, exportSchema = true)
abstract class WordRoomDatabase : RoomDatabase() {
abstract fun wordDao(): WordDao
private class WordDatabaseCallback(
private val scope: CoroutineScope
) :Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
INSTANCE?.let { database ->
scope.launch {
var wordDao = database.wordDao()
// Add sample words.
var word = Word("Hello","GH")
wordDao.insertWord(word)
word = Word("World!","HJ")
wordDao.insertWord(word)
}
}
}
}
companion object {
@Volatile
private var INSTANCE: WordRoomDatabase? = null
fun getDatabase(
context: Context,
scope: CoroutineScope
): WordRoomDatabase {
// if the INSTANCE is not null, then return it,
// if it is, then create the database
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
WordRoomDatabase::class.java,
"word_database"
)
.addCallback(WordDatabaseCallback(scope))
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
// return instance
instance
}
}
}
}
WordRepository.kt
// Declares the DAO as a private property in the constructor. Pass in the DAO
// instead of the whole database, because you only need access to the DAO
class WordRepository(private val wordDao: WordDao) {
// Room executes all queries on a separate thread.
// Observed Flow will notify the observer when the data has changed.
val allWords: Flow<List<Word>> = wordDao.getAlphabetizedWords()
// By default Room runs suspend queries off the main thread, therefore, we don't need to
// implement anything else to ensure we're not doing long running database work
// off the main thread.
@Suppress("RedundantSuspendModifier")
@WorkerThread
suspend fun insert(word: Word) {
wordDao.insertWord(word)
}
}
Viewmodel 类 WordViewModel.kt
class WordViewModel(private val repository: WordRepository) : ViewModel() {
// Using LiveData and caching what allWords returns has several benefits:
// - We can put an observer on the data (instead of polling for changes) and only update the
// the UI when the data actually changes.
// - Repository is completely separated from the UI through the ViewModel.
val allWords: LiveData<List<Word>> = repository.allWords.asLiveData()
/**
* Launching a new coroutine to insert the data in a non-blocking way
*/
fun insert(word: Word) = viewModelScope.launch {
repository.insert(word)
}
}
class WordViewModelFactory(private val repository: WordRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(WordViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return WordViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
WordApplication.kt
class WordsApplication : Application() {
// No need to cancel this scope as it'll be torn down with the process
val applicationScope = CoroutineScope(SupervisorJob())
// Using by lazy so the database and the repository are only created when they're needed
// rather than when the application starts
val database by lazy { WordRoomDatabase.getDatabase(this,applicationScope) }
val repository by lazy { WordRepository(database.wordDao()) }
}
新的Wordactivity.kt
class NewWordActivity : AppCompatActivity() {
private lateinit var editWordView: EditText
private lateinit var editDef:EditText
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.new_word)
editWordView = findViewById(R.id.edit_word)
val button = findViewById<Button>(R.id.button_save)
button.setOnClickListener {
val replyIntent = Intent()
if (TextUtils.isEmpty(editWordView.text)) {
setResult(Activity.RESULT_CANCELED, replyIntent)
} else {
val word = editWordView.text.toString()
val def = editDef.text.toString()
replyIntent.putExtra(EXTRA_REPLY1, word)
replyIntent.putExtra(EXTRA_REPLY2,def)
setResult(Activity.RESULT_OK, replyIntent)
}
finish()
}
}
companion object {
const val EXTRA_REPLY1 = "com.example.android.wordlistsql.REPLY"
const val EXTRA_REPLY2 = "com.example.android.word"
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
private val newWordActivityRequestCode = 1
private val TAG = "heyy"
private val wordViewModel: WordViewModel by viewModels {
WordViewModelFactory((application as WordsApplication).repository)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.recyclerview)
val adapter = WordListAdapter()
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)
wordViewModel.allWords.observe(this, Observer { words ->
// Update the cached copy of the words in the adapter.
words?.let { adapter.submitList(it) }
})
val fab = findViewById<FloatingActionButton>(R.id.fab)
fab.setOnClickListener {
val intent = Intent(this@MainActivity, NewWordActivity::class.java)
startActivityForResult(intent, newWordActivityRequestCode)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == newWordActivityRequestCode && resultCode == Activity.RESULT_OK) {
val word = data?.getStringExtra(NewWordActivity.EXTRA_REPLY1)
val def = data?.getStringExtra(NewWordActivity.EXTRA_REPLY2)
if (!word.isNullOrEmpty() && !def.isNullOrEmpty()) {
val newWord = Word(word, def)
try {
wordViewModel.insert(newWord)
Log.d(TAG, "Inserted new word: $newWord")
} catch (e: Exception) {
Log.e(TAG, "Failed to insert new word: $newWord", e)
}
} else {
Log.w(TAG, "Word or definition is empty or null")
}
} else {
Log.w(TAG, "New word activity returned with non-OK result code: $resultCode")
Toast.makeText(
applicationContext,
R.string.empty_not_saved,
Toast.LENGTH_LONG
).show()
}
}
}
我们还声明了 Adapter 类来通过它显示数据。 WordListAdapter.kt
class WordListAdapter : ListAdapter<Word, WordListAdapter.WordViewHolder>(WordsComparator()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WordViewHolder {
return WordViewHolder.create(parent)
}
override fun onBindViewHolder(holder: WordViewHolder, position: Int) {
val current = getItem(position)
holder.bind(current.word)
}
class WordViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val wordItemView: TextView = itemView.findViewById(R.id.textView)
private val deftext:TextView = itemView.findViewById(R.id.text1)
fun bind(text: String?) {
wordItemView.text = text
deftext.text=text
}
companion object {
fun create(parent: ViewGroup): WordViewHolder {
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.recycler_view, parent, false)
return WordViewHolder(view)
}
}
}
class WordsComparator : DiffUtil.ItemCallback<Word>() {
override fun areItemsTheSame(oldItem: Word, newItem: Word): Boolean {
return oldItem === newItem
}
override fun areContentsTheSame(oldItem: Word, newItem: Word): Boolean {
return oldItem.word == newItem.word
}
}
}
虽然我不太确定,但我觉得我在 onActivityResult 方法中做错了什么,当我尝试通过 Editext 仅实现一个数据时,它确实有效并向我显示了显示的数据,尽管当我尝试添加另一个词时,它没有t保存。