首页 > 解决方案 > room kotlin 通过 val 从另一个片段查询项目列表

问题描述

花了很多时间试图解决这个问题,最后决定在这里寻求帮助。

我的活动包含两个片段。第一个有一个 recyclerview 从 db (书单)填充 onCreate 。单击一个项目,我将项目 ID 传递给第二个片段,女巫应该显示来自单个作者的书籍。在第二个中,我检索了 id 但未能实现正确的方法来查询所选作者的书籍。

书桌

@Entity(
    tableName = TABLE_NAME,
    foreignKeys = [ForeignKey(
        entity = Author::class,
        parentColumns = ["tid"],
        childColumns = [AUTHOR_ID],
        onDelete = ForeignKey.CASCADE
    )],
    indices = [Index(TITLE), Index(AUTHOR_ID)]
)
data class Book(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "bid") var id: Long = 0,
    @ColumnInfo(name = TITLE) var title: String,
    @ColumnInfo(name = AUTHOR_ID) var authorId: Long) {

    companion object {
        const val TABLE_NAME = "book"
        const val TITLE = "title"
        const val AUTHOR_ID = "authorId"
    }

书道

@Dao
interface BookDao {

    @Query("SELECT * FROM book WHERE title = :title LIMIT 1")
    suspend fun findBookByTitle(title: String?): Book?

    // other queries here

    @Query("SELECT * FROM book WHERE authorId (:athId)")
    fun getBokByAth(vararg athId: Int?): LiveData<List<Book>>

}

书库

class BookRepository(private val bookDao: BookDao) {

    fun getBokByAth(author: Book>): LiveData<List<Book>> {
        return bookDao.getBokByAth()

    }
}

图书视图模型

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

    private val bokRepository: BookRepository

    private val bookDao: BookDao = CollecteDatabase.getDatabase(application).bookDao()
    private val authorDao: AuthorDao = CollecteDatabase.getDatabase(application).authorDao()

    val booksList: LiveData<List<Book>>
    val bokByAth: LiveData<List<Book>>
    val authorsList: LiveData<List<Author>>

    init {
        val bookDao: BookDao = CollecteDatabase.getDatabase(application).bookDao()
        bokRepository = BookRepository(bookDao)

        bokByAth = bookDao.getBokByAth()
        booksList = bookDao.allBooks
        authorsList = authorDao.allAuthors
    }
    fun getBokByAth(vararg book: Book): LiveData<List<Book>> {
        return bokRepository.getBokByAth(book)
    }

    // other queries here

}

BooksListAdapter

class BooksListAdapter(private val parent: Fragment) : RecyclerView.Adapter<BooksViewHolder>() {

    private val layoutInflater: LayoutInflater = LayoutInflater.from(parent.requireContext())
    private var bookList: List<Book>? = null

    fun setBookList(bookList: List<Book>?) {
        this.bookList = bookList
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BooksViewHolder {
        val itemView = layoutInflater.inflate(R.layout.item_list_book, parent, false)
        return BooksViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: BooksViewHolder, position: Int) {
        bookList?.let { list ->
            val book = list[position]
            holder.titleText.text = book.title
            runBlocking {
                val authorFullName = withContext(Dispatchers.Default) {
                    getAuthFullName(book)
                }

                holder.authorText.text = authorFullName ?: ""

                holder.itemView.setOnClickListener {
                    val dialogFragment: DialogFragment = newInstance(book.title, authorFullName)
                    dialogFragment.setTargetFragment(parent, 99)
                    dialogFragment.show(
                        (parent.activity as AppCompatActivity).supportFragmentManager,
                        BookSaveDialogFragment.TAG_DIALOG_BOOK_SAVE
                    )
                }
            }
        }
    }

    private suspend fun getAuthorFullName(book: Book): String? {
        return CollecteDatabase.getDatabase(parent.requireContext()).authorDao().findAuthorById(book.authorId)?.authorNom
    }

    override fun getItemCount(): Int {
        return if (bookList == null) {
            0
        } else {
            book!!.size
        }
    }

    class BooksViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val titleText: TextView = itemView.findViewById(R.id.tvBookTitle)
        val authorText: TextView = itemView.findViewById(R.id.tvBookAuthorFullName)
    }
}

书籍列表片段

class BooksListFragment : Fragment() {

    private lateinit var booksListAdapter: BooksListAdapter
    private lateinit var booksViewModel: BooksViewModel
    private lateinit var booksList: List<Book>
    private lateinit var booksByAuthoList: List<Book>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initData()
    }

    var clickedPos: Int? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_books, container, false)

        initView(view)
        return view
    }

    private fun initData() {

        // here I get the author id from the first fragment

        clickedPos = arguments?.getInt("clicked_pos")

        // I assign it to Int var and late I got problem with cause the query requires a Book type 

        var athId = clickedPos


        booksViewModel = ViewModelProvider(this).get(BooksViewModel::class.java)
        booksViewModel.getBokByAth().observe(this,
            Observer { books: List<Book>->
                booksByAuthotList = books
                booksListAdapter.setBookList(books)
                Log.d(
                    TAG,
                    "¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤  " +
                            "\n from BooksListFragment.kt => ClickItemID : ${clickedPos}  ===> ${books} " +
                            "\n ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤"
                )
            }
        )

        booksViewModel.authorsList.observe(this,
            Observer { _ ->
                booksViewModel.getBokByAth().value?.let {
                    booksByAuthorList = it
                    booksListAdapter.setBookList(it)
                }
            }
        )
    }

    private fun initView(view: View) {
        val recyclerView: RecyclerView = view.findViewById(R.id.recyclerview_books)
        booksListAdapter = BooksListAdapter(this)
        recyclerView.adapter = booksListAdapter
        recyclerView.layoutManager = LinearLayoutManager(requireContext())
    }

    fun removeData() {
        GlobalScope.launch(Dispatchers.IO) { booksViewModel.deleteAll() }
    }

    companion object {
        fun newInstance(): BooksListFragment = BooksListFragment()
    }
}

非常感谢

Edit#1 编译错误:

06-14 13:59:20.120 17418-17418/com.name.package D/ContentValues: ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤  
     Clicked Item ID: 2 
     ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
06-14 13:59:20.140 17418-17418/com.name.package D/CubicBezierInterpolator: CubicBezierInterpolator  mControlPoint1x = 0.15, mControlPoint1y = 0.7, mControlPoint2x = 0.2, mControlPoint2y = 0.98
// ************************other lines
06-14 13:59:20.152 17418-18055/com.name.package E/SQLiteLog: (1) 
06-14 13:59:20.163 17418-18055/com.name.package E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_1
    Process: com.name.package, PID: 17418
    java.lang.RuntimeException: Exception while computing database live data.
        at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:92)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
        at java.lang.Thread.run(Thread.java:833)
     Caused by: android.database.sqlite.SQLiteException: near "=": syntax error (Sqlite code 1): , while compiling: SELECT * FROM book WHERE authorId =, (OS error - 11:Try again)
        // *********************** other lines 
        at androidx.sqlite.db.framework.FrameworkSQLiteDatabase.query(FrameworkSQLiteDatabase.java:161)
        at androidx.room.RoomDatabase.query(RoomDatabase.java:328)
        at androidx.room.util.DBUtil.query(DBUtil.java:83)
        at com.name.package.db.BookDao_Impl$9.call(BookDao_Impl.java:238)
        at com.name.package.db.BookDao_Impl$9.call(BookDao_Impl.java:235)
        at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:90)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
        at java.lang.Thread.run(Thread.java:833) 
06-14 13:59:20.312 17418-18055/com.name.package I/Process: Sending signal. PID: 17418 SIG: 9

BookDao_iml 第 235 到 238 行

return __db.getInvalidationTracker().createLiveData(new String[]{"book"}, false, new Callable<List<Book>>() {
      @Override
      public List<Book> call() throws Exception {
        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);

标签: androidkotlinfragmentviewmodel

解决方案


推荐阅读