skip to Main Content

I am studying with Kotlin and I have not been able to solve the error for several days, so I am asking for help.
I am trying to retrieve data from the room database and put it into a variable(productlist), but an error occurs as follows.

kotlin.UninitializedPropertyAccessException: lateinit property productList has not been initialized

Here is my source codes. I already checked that the room database contains data normally.
I want to put data fetched from db in productList variable and use it.
Thanks in advance!

[MainActivity.kt]
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var PACKAGE_NAME: String
    private var currentPosition: Int = 0
    private var lastPosition: Int = 0
    private lateinit var db: AppDatabase
    private lateinit var productDao: ProductDao
    private lateinit var productList: List<ProductEntity>
    private var urls: String = ""
    private var titles: String = ""
    private var descs: String = ""
    private var isVideos: String = ""

    override fun onCreate(savedInstanceState: Bundle?) {
     
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        db = AppDatabase.getInstance(this)!!
        productDao = db.getProductDao()
        setVideoItem()
    }

    private fun setVideoItem() {
        val videosViewPager = binding.viewPagerVideos
        val videoItems: MutableList<VideoItem> = ArrayList()
        val files = File([email protected], "products").listFiles()
        Thread {
            productList = productDao.getAll()
        }.start()
        for (i in productList) { //I want to store accessed data to productList variable 
            urls += "${i.idx}:"
            titles += "${i.name}:"
            descs += "${i.price}:"
        }
        println("urls:$urls")
        println("titles:$titles")
        println("descs:$descs")

    }
[ProductDao.kt]
@Dao
interface ProductDao {
    @Query("select * from ProductEntity")
    fun getAll() : List<ProductEntity>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertAll(product: ProductEntity)

    @Query("select idx, name, price from ProductEntity where idx like :searchIdx")
    fun searchProductByIdx(searchIdx: String) : ProductEntity

}

3

Answers


  1. productDao.getAll() is called on a separate thread which takes time to execute. So you’re trying to access productList before the thread initializes it.

    It’s race condition in which the thread always loses.

    Relocating the code that uses productList to the thread should solve this race:

    Thread {
        productList = productDao.getAll()
        for (i in productList) { 
            urls += "${i.idx}:"
            titles += "${i.name}:"
            descs += "${i.price}:"
        }
        println("urls:$urls")
        println("titles:$titles")
        println("descs:$descs")
    }.start()
    
    Login or Signup to reply.
  2. Thread {
                productList = productDao.getAll()
            }.start()
    

    Product list is being fetched in a thread in a parallel process so since it is not synchronous when the control is on the line for (i in productList) according to the program the product list has not been initialized.. You have to decide how you handle this concurrency. either call the method synchronously or populate the list after iteration via some method or do it in the same thread .

    Something like

    Thread {
        productList = productDao.getAll()
        //iterate through the list 
        //print the values
    }.start()
    
    Login or Signup to reply.
  3. Start a thread to access db,it will take some time.The main thread will not wait for the thread accessing the database to complete, so it is uninitialized to read productList at this time.

    You can access the list after loading is complete, or use Android Handler to notify the main thread of the update after loading is complete.

    Thread {
            productList = productDao.getAll()
            for (i in productList) {
                urls += "${i.idx}:"
                titles += "${i.name}:"
                descs += "${i.price}:"
            }
            println("urls:$urls")
            println("titles:$titles")
            println("descs:$descs")
    }.start()
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search