मैं रूम और कोटलिन के लिए नया हूं, और मैं एक साधारण रूम का डेटाबेस बनाने और इसे एक रीसाइक्लर व्यू में प्रस्तुत करने की कोशिश कर रहा हूं जो व्यूपेजर में बैठता है।
गतिविधि में एक ViewPager ऑब्जेक्ट होता है, जिसमें ViewPager में एक Fragment होता है, और उस Fragment में एक RecyclerView होता है: गतिविधि -> 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
}
}
}
गतिविधि:
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()
}
}
टुकड़ा:
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
}
}
1 उत्तर
आपका कोड काम क्यों नहीं करता है, यह समझने के लिए आपको मल्टी-थ्रेडिंग की अवधारणा को समझने की आवश्यकता है। संक्षेप में, आपको एक खाली सूची मिल रही है क्योंकि आप मुख्य थ्रेड में सूची प्राप्त करने का प्रयास कर रहे हैं, जबकि आपका सम्मिलन और वर्कर थ्रेड पर चल रही क्वेरी अभी तक पूरी नहीं हुई है।
मैंने निष्पादन के क्रम की व्याख्या करने के लिए टिप्पणी को कोड में डाल दिया। टिप्पणी में संख्या पूर्ण होने का क्रम है:
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
}
data
सूची को adapter
को असाइन करने से पहले आपको dbWorkerThread के अपना कार्य पूरा करने के लिए प्रतीक्षा करने की आवश्यकता है। सबसे सरल समाधानों में से एक पर एक नज़र डालें:
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)
}
ध्यान रखें कि यह निश्चित रूप से इस समस्या से निपटने का सबसे अच्छा तरीका नहीं है। यह एक बहुत ही आम समस्या है और ऐसे कई समाधान हैं जो अधिक पठनीय, लचीले और रखरखाव योग्य हैं। यह सिर्फ इतना है कि अन्य समाधानों के लिए गहरी समझ की आवश्यकता होती है और मल्टी-थ्रेडिंग इतना व्यापक विषय है कि मैं उन सभी को एक SO उत्तर में नहीं समझा सकता। मुझे आशा है कि आप सामान्य विचार प्राप्त कर लेंगे और आपको इसके अन्य समाधानों का पता लगाने के लिए प्रोत्साहित करेंगे।
संबंधित सवाल
नए सवाल
android
एंड्रॉइड Google का मोबाइल ऑपरेटिंग सिस्टम है, जिसका उपयोग प्रोग्रामिंग या डिजिटल डिवाइस (स्मार्टफोन, टैबलेट, ऑटोमोबाइल्स, टीवी, वियर, ग्लास, IoT) को विकसित करने के लिए किया जाता है। एंड्रॉइड से संबंधित विषयों के लिए, एंड्रॉइड-विशिष्ट टैग जैसे कि एंड्रॉइड-इरादे, एंड्रॉइड-गतिविधि, एंड्रॉइड-एडॉप्टर आदि का उपयोग करें। विकास या प्रोग्रामिंग के अलावा अन्य प्रश्नों के लिए, लेकिन एंड्रॉइड फ्रेमवर्क से संबंधित हैं, इस लिंक का उपयोग करें: https: // android.stackexchange.com।