android - 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);
解决方案
推荐阅读
- python - 按字母顺序排序后重新排列 GeoPandas 索引
- python-3.x - 转换为 SQL 时 SQLAlchemy 出错
- git - 删除文件命令行/git
- installation - Inno Setup:重复 InitializeSetup 合并
- bootstrap-4 - 如何更改默认的 Bootstrap 手风琴按钮?
- google-apps-script - 在 HTML 中的 successHandler 函数中看不到来自服务器端函数的 GAS 数据
- python - 通过 BeautifulSoup 将文本从 html 抓取并保存到 csv
- python - 为什么我的动画在 PyCharm 中有效,但在 Spyder 中无效?
- sql - 在 postgresql 中创建主键需要几天时间
- android - 自 `androidx-livedata` 更新 2.3.0 以来,lint 分析期间出现意外失败