与Kotlin一对多的房间

问题描述 投票:0回答:1

任务是选择一个日记时,打开一个带有此日记注释的活动。(一对多)这就是数据库中实体的样子:

@Entity(tableName = "word_table")
data class Word(@ColumnInfo(name = "word") val word: String,
                @ColumnInfo(name = "description") val description : String
)
{
    @ColumnInfo(name = "id")
    @PrimaryKey(autoGenerate = true)
    var id : Long = 0

}

@Entity(tableName = "note_table")
data class Note(@ColumnInfo(name = "note_name") val note : String,
                @ColumnInfo(name = "text") val text : String,
                @ColumnInfo(name = "diaryId") val diaryId : Long
){
    @PrimaryKey(autoGenerate = true)
    var idNote : Long = 0
    }

在NoteRepository.kt中使用数据类

data class NotesAndWords (@Embedded val word : Word,
                          @Relation(parentColumn = "id", entityColumn = "diaryId")
                          val notes : List<Note>)

以及WordDao.kt中的查询

@Transaction
@Query("SELECT * from word_table ")
fun getSomeNotes() : LiveData<List<NotesAndWords>>

我得到数据并将其保存在NoteRepository类中:

class NoteRepository (private val wordDao : WordDao) {

    var allNotes : LiveData<List<NotesAndWords>> = wordDao.getSomeNotes()

    suspend fun insertNote(note : Note)
    {
        wordDao.insertNote(note)
    }
}

然后通过NoteViewModel.kt将数据传递到NoteActivity.kt:

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

    private val repository: NoteRepository

    val allNotes: LiveData<List<NotesAndWords>>

    init {

        val wordsDao = WordRoomDatabase.getDatabase(application, viewModelScope).wordDao()

        repository = NoteRepository(wordsDao)
        allNotes = repository.allNotes

    }

    fun insertNote(note: Note) = viewModelScope.launch {
        repository.insertNote(note)
    }
}

((NoteActivity.kt)]

class NoteActivity : AppCompatActivity() {

    private val newWordActivityRequestCode = 1
    private lateinit var noteViewModel: NoteViewModel

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

        val adapter = NoteListAdapter(this, intent.getLongExtra("tag", -1) ){

            val intent = Intent(this, ClickedActivity::class.java)
            intent.putExtra("tag", it.note)
            startActivity(intent)

        }

        recyclerview1.adapter = adapter
        recyclerview1.layoutManager = LinearLayoutManager(this)
        noteViewModel = ViewModelProvider(this).get(NoteViewModel::class.java)

        noteViewModel.allNotes.observe(this, Observer {
            adapter.setNotes(it)
        })

        val fab = findViewById<FloatingActionButton>(R.id.fab)
        fab.setOnClickListener {
            val intent = Intent(this, 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)
        {
            data?.getStringArrayListExtra(NewWordActivity.EXTRA_REPLY)?.let {
                val note = Note(it[0], it[1], intent.getLongExtra("tag", -1))
                noteViewModel.insertNote(note)
            }
        }
        else
        {
            Toast.makeText(applicationContext, R.string.empty_not_saved,
                Toast.LENGTH_LONG).show()
        }
    }

然后,在适配器中,我使用MutableMap来转换列表,以便键是名称ID,值是根据请求选择的注释(附加到特定的日记)

NoteListAdapter.kt:

class NoteListAdapter internal constructor(
    context: Context,
    val wordId: Long,
    private val listener : (Note) -> Unit
) : RecyclerView.Adapter<NoteListAdapter.NoteViewHolder>() {

    private val inflater: LayoutInflater = LayoutInflater.from(context)

    //private val mContext = context

    private var notes = emptyList<NotesAndWords>()   // Cached copy of words
    private var notesMapped = mutableMapOf<Long, List<Note>>()

    inner class NoteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {


        private val noteItemView: TextView = itemView.findViewById(R.id.textView1)

        private val noteDescriptionView: TextView = itemView.findViewById(R.id.textView)

        fun bindView(note: Note, listener : (Note) -> Unit) {



                noteItemView.text = note.diaryId.toString()

                noteDescriptionView.text = note.text

            itemView.setOnClickListener {
                listener(note)
            }

        }

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {


        val itemView = inflater.inflate(R.layout.recyclerview_layout, parent,
            false)

        return NoteViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
        holder.bindView(notesMapped[wordId]!![position], listener)
    }

    internal fun setNotes(notes: List<NotesAndWords>) {
        this.notes = notes

        for (i in this.notes) {
            notesMapped[i.word.id] = i.notes
        }

        notifyDataSetChanged()
    }
    override fun getItemCount() = notesMapped[wordId]!!.size
}

数据库:

@Database(entities = [Word::class, Note::class], version = 2, exportSchema = false)
abstract class WordRoomDatabase : RoomDatabase() {

    abstract fun wordDao(): WordDao

    private class WordDatabaseCallback(private val scope: CoroutineScope) : RoomDatabase.Callback()
    {

        override fun onOpen(db: SupportSQLiteDatabase) {
            super.onOpen(db)
            INSTANCE?.let { database ->
                scope.launch {
                    populateDatabase(database.wordDao())
                }
            }
        }

        suspend fun populateDatabase(wordDao: WordDao) {


            //wordDao.deleteAll()
            //wordDao.deleteAllNotes()

        }
    }

    companion object {

        @Volatile
        private var INSTANCE: WordRoomDatabase? = null

        fun getDatabase(context: Context, scope:CoroutineScope): WordRoomDatabase {
            val tempInstance = INSTANCE
            if (tempInstance != null) {
                return tempInstance
            }
            val instance = Room.databaseBuilder(context.applicationContext,
                WordRoomDatabase::class.java, "word_database")
                .addCallback(WordDatabaseCallback(scope))
                //.fallbackToDestructiveMigration()
                .build()
            INSTANCE = instance
            return instance
        }
    }
}

我已经创建了几本日记和一个便笺,使用按钮来创建新的日记和便笺。现在,如果您依次选择多个日记,则在尝试选择日记时,适配器将在此行中发出NullPointerException:

override fun getItemCount() = notesMapped[wordId]!!.size

如果notesMapped始终具有wordId键,为什么会引发此异常?

NoteActivity是从另一个活动调用的,并且日记ID传递给了它

此库在GitHub上:https://github.com/Lomank123/RoomDatabase

任务是选择一个日记时,打开一个带有此日记注释的活动。 (一对多)数据库中的实体如下所示:@Entity(tableName =“ word_table”)数据...

android kotlin android-room android-livedata android-viewmodel
1个回答
0
投票

您好,地图是空的,地图返回的是空值,您正在检查空对象的大小。同样好的做法是,不要使用地图,而只使用注释列表,然后直接传递该列表。

© www.soinside.com 2019 - 2024. All rights reserved.