मैं रूम और कोटलिन के लिए नया हूं, और मैं एक साधारण रूम का डेटाबेस बनाने और इसे एक रीसाइक्लर व्यू में प्रस्तुत करने की कोशिश कर रहा हूं जो व्यूपेजर में बैठता है।

गतिविधि में एक 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
Geeky bean 2 मार्च 2019, 17:40

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 उत्तर में नहीं समझा सकता। मुझे आशा है कि आप सामान्य विचार प्राप्त कर लेंगे और आपको इसके अन्य समाधानों का पता लगाने के लिए प्रोत्साहित करेंगे।

1
Sanlok Lee 3 मार्च 2019, 00:40