gpt4 book ai didi

android - 使用 RecyclerView 的房间数据库 View

转载 作者:搜寻专家 更新时间:2023-10-30 23:27:19 33 4
gpt4 key购买 nike

我是 Room 和 Kotlin 的新手,我正在尝试构建一个简单的 Room 数据库并将其呈现在位于 ViewPager 中的 RecyclerView 中。

Activity包含一个ViewPager对象,那个ViewPager包含一个Fragment,那个Fragment包含一个RecyclerView: Activity --> ViewPager --> fragment --> RecyclerView

我遇到的问题是,当我尝试接收数据库时(插入后),我得到的是空值。

代码:

@Entity(tableName = "Guests_table")
data class Guest(@NonNull @ColumnInfo (name = "Name") var name: String,
@ColumnInfo (name = "Phone number") var phoneNumber: String,
@ColumnInfo (name = "Coming") var coming: Boolean = false,
@ColumnInfo (name = "Participants") var participants: Int)
{
@PrimaryKey (autoGenerate = true)
var id: Long = 0

init
{
phoneNumber = PhoneNumberUtils.formatNumber(phoneNumber, Locale.getDefault().country)
}
}

道:

@Dao
interface GuestsDAO
{
@Insert
fun insert(guest: Guest)

@Delete
fun delete(guest: Guest)

@Query ("DELETE FROM Guests_table")
fun deleteAll()

@Query ("SELECT * FROM Guests_table ORDER BY name ASC")
fun getAllGuests(): List<Guest>
}

数据库:

@Database(entities = [Guest::class], version = 1)
abstract class InviterRoomDatabase: RoomDatabase()
{
abstract fun guestsDao(): GuestsDAO

companion object
{
private var INSTANCE: InviterRoomDatabase ?= null

fun getDatabase(context: Context): InviterRoomDatabase?
{
if (INSTANCE == null)
{
synchronized(InviterRoomDatabase::class)
{
INSTANCE = Room.databaseBuilder(context.applicationContext,InviterRoomDatabase::class.java,"Guests.db").build()
}
}

return INSTANCE
}

fun destroyInstance()
{
INSTANCE = null
}
}
}

Activity :

class EventActivity : AppCompatActivity()
{
private lateinit var viewPager: ViewPager

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

viewPager = findViewById(R.id.guests_view_pager)
val pagerAdapter = EventPagerAdapter(supportFragmentManager)
viewPager.adapter = pagerAdapter
}
}

适配器:

class EventPagerAdapter(fragmentManager: FragmentManager): FragmentPagerAdapter(fragmentManager)
{

override fun getCount(): Int
{
return 1
}

override fun getItem(position: Int): Fragment
{
return GuestListFragment.newInstance()
}
}

fragment :

class GuestListFragment : Fragment()
{
private var guestsDataBase: InviterRoomDatabase? = null
private lateinit var dbWorkerThread: DBWorkerThread

companion object
{
fun newInstance(): GuestListFragment
{
val fragment = GuestListFragment()
return fragment
}
}


override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
{

dbWorkerThread = DBWorkerThread("workerThread")
dbWorkerThread.start()
guestsDataBase = InviterRoomDatabase.getDatabase(this.context!!)
insertGuestToDB(Guest("Joe","052352332",false,0))

var rootView = inflater.inflate(R.layout.fragment_guest_list, container, false)
var rv: RecyclerView = rootView.findViewById(R.id.guests_list_recycler_view)
rv.layoutManager = LinearLayoutManager(context)

var d = getAllDataFromDB()
rv.adapter = GuestsRecycleViewAdapter.newInstance(d)

return rootView
}


private fun insertGuestToDB(guest: Guest)
{
val task = Runnable {guestsDataBase?.guestsDao()?.insert(guest)}
dbWorkerThread.postTask(task)
}

private fun getAllDataFromDB(): List<Guest>
{
var data: List<Guest> = emptyList()
val task = Runnable { data = guestsDataBase?.guestsDao()?.getAllGuests()!!}

dbWorkerThread.postTask(task)

return data
}
}

最佳答案

您需要了解多线程的概念才能理解为什么您的代码不起作用。简而言之,您得到一个空列表是因为您试图在主线程中获取列表,而在工作线程上运行的插入和查询尚未完成。

我把注释放在代码里,说明执行顺序。评论中的数字为完成顺序:


override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? 
{
// [1] onCreateView starts on main thread.
dbWorkerThread = DBWorkerThread("workerThread")
dbWorkerThread.start()
guestsDataBase = InviterRoomDatabase.getDatabase(this.context!!)
// [2] calls insertGuestToDB on main thread.
insertGuestToDB(Guest("Joe","052352332",false,0))

var rootView = inflater.inflate(R.layout.fragment_guest_list, container, false)
var rv: RecyclerView = rootView.findViewById(R.id.guests_list_recycler_view)
rv.layoutManager = LinearLayoutManager(context)

// [4] calls getAllDataFromDB on main thread.
var d = getAllDataFromDB()
// [6] get "d" on main thread. "d" is an empty list.
rv.adapter = GuestsRecycleViewAdapter.newInstance(d)

return rootView
}


private fun insertGuestToDB(guest: Guest)
{
// [2] insertGuestToDB executed on main thread.
val task = Runnable {
guestsDataBase?.guestsDao()?.insert(guest)
// [7] insertion finished on worker thread.
}
dbWorkerThread.postTask(task)
// [3] insertGuestToDB finishes on main thread.
}

private fun getAllDataFromDB(): List<Guest>
{
// [4] getAllDataFromDB on main thread. "data" points to an empty list
var data: List<Guest> = emptyList()
val task = Runnable {
data = guestsDataBase?.guestsDao()?.getAllGuests()!!
// [8] query finishes on worker thread, but "data" is now lost.
}
dbWorkerThread.postTask(task)

// [5] returns on main thread. "data" still points to an empty list
return data
}


您需要做的是等待 dbWorkerThread 完成其工作,然后再将 data 列表分配给 adapter。看一下最简单的解决方案之一:


var rv: RecyclerView

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
{

dbWorkerThread = DBWorkerThread("workerThread")
dbWorkerThread.start()

var rootView = inflater.inflate(R.layout.fragment_guest_list, container, false)
rv= rootView.findViewById(R.id.guests_list_recycler_view)
rv.layoutManager = LinearLayoutManager(context)

guestsDataBase = InviterRoomDatabase.getDatabase(this.context!!)
insertGuestToDbAndUpdateRv(Guest("Joe","052352332",false,0))

return rootView
}


private fun insertGuestToDbAndUpdateRv(guest: Guest)
{
val task = Runnable {
// 1. Insert on a worker thread.
guestsDataBase?.guestsDao()?.insert(guest)

// 2. Query on a worker thread.
var data = guestsDataBase?.guestsDao()?.getAllGuests()!!
this@GuestListFragment.getActivity().runOnUiThread {
// 3. Once they are done, update ui on main thread.
rv.adapter = GuestsRecycleViewAdapter.newInstance(data)
}
}
dbWorkerThread.postTask(task)
}


请注意,这绝对不是解决此问题的最佳方法。这是一个非常普遍的问题,并且有大量不同的解决方案更具可读性、灵 active 和可维护性。只是其他解决方案需要更深入的理解,而多线程是一个广泛的主题,我无法在一个 SO 答案中解释所有这些。不过,我希望您能了解总体思路,并鼓励您探索其他解决方案。

关于android - 使用 RecyclerView 的房间数据库 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54959663/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com