I am unable to solve a seemingly trivial issue. My problem is probably my lack of experience (and understanding) of the Kotlin language. Nevertheless, I'll be needing help with this.
I made a custom class, containing a custom function. It seems simple enough, but I keep getting the "unresolved reference" error when I try to use this function.
This piece of example code reproduces the error:
abstract class Test {
private var test: Test? = null
fun getBla(): Test? {
return test
}
fun shout() {
println("Whaaaaa!")
}
}
fun main(args: Array<String>) {
val tst = Test.getBla()
tst.shout()
}
The error reads Unresolved reference: getBla
The class may not make a lot of sense like this, but it is intended to mimic the structure of the actual class I am using in my app.
I feel I'm making a terrible rookie mistake. I've searched on Stackoverflow and Kotlin documentation, but I can't seem to find a solution.
I tested the above code on try.kotlinlang.org , by simply replacing the "hello world" example.
#### EDITI'm afraid the context of the app I'm trying to build might be important after all. I'm trying to implement a Room database, but the clearest tutorial I could find is for Java, so I'm trying to translate and that makes me run into trouble.
This is the page I'm currently following: Room Database . I need the "Test" class here to be a singleton, that's what the actual contents of "getBla()" were for.
To get to actual problem, here's what the actual class looks like now:
@Database(entities = [(Box::class)], version = 1) abstract class BoxRoomDatabase : RoomDatabase() { abstract fun boxDao(): BoxDao private var boxRoomDatabase: BoxRoomDatabase? = null fun getDatabase(context: Context): BoxRoomDatabase? { if (boxRoomDatabase == null) { //Double colon allows to get the Java class instead of a KClass, which is not equivalent synchronized<Unit>(BoxRoomDatabase::class.java) { boxRoomDatabase = Room.databaseBuilder(context.applicationContext, BoxRoomDatabase::class.java, "box_database") .build() } } return boxRoomDatabase } }
So BoxRoomDatabase
needs to be a singleton. The problem arises from the automatic translation of Java code into Kotlin. It seems this situation is a bit too complex for that. I tried to find an answer by searching for various combination of "Kotlin", "Singleton" and "abstract method". Eventually I stumbled upon this blog: Kotlin singletons with argument . What I needed was a singleton that takes an argument, which apparently was not a trivial thing to do in Kotlin. This blog explains how to implement such a construct.
My code now at least compiles, if it actually does what I want it to do I'll find out later. My current implementation is somewhat like this:
SingletonHolder.kt (To build singletons taking arguments)
import android.arch.persistence.room.RoomDatabase
import android.arch.persistence.room.Database
import android.content.Context
import android.arch.persistence.room.Room
@Database(entities = [(Box::class)], version = 1)
abstract class BoxRoomDatabase : RoomDatabase() {
abstract fun boxDao(): BoxDao
private var boxRoomDatabase: BoxRoomDatabase? = null
companion object : SingletonHolder<BoxRoomDatabase, Context>({
Room.databaseBuilder(it.applicationContext,
BoxRoomDatabase::class.java, "box_database")
.build()
})
}
BoxRoomDatabase.kt
class BoxRepository internal constructor(application: Application) {
private val mBoxDao: BoxDao
private val mAllBoxes: LiveData<List<Box>>
init {
mBoxDao = BoxRoomDatabase.getInstance(application).boxDao()
mAllBoxes = mBoxDao.getAllBoxes()
}
fun getAllBoxess(): LiveData<List<Box>> {
return mAllBoxes
}
fun insert(box: Box) {
InsertAsyncTask(mBoxDao).execute(box)
}
private class InsertAsyncTask internal constructor(private val mAsyncTaskDao: BoxDao) : AsyncTask<Box, Void, Void>() {
override fun doInBackground(vararg params: Box): Void? {
mAsyncTaskDao.insert(params[0])
return null
}
}
}
BoxRepository.kt
class BoxRepository internal constructor(application: Application) { private val mBoxDao: BoxDao private val mAllBoxes: LiveData<List<Box>> init { mBoxDao = BoxRoomDatabase.getInstance(application).boxDao() mAllBoxes = mBoxDao.getAllBoxes() } fun getAllBoxess(): LiveData<List<Box>> { return mAllBoxes } fun insert(box: Box) { InsertAsyncTask(mBoxDao).execute(box) } private class InsertAsyncTask internal constructor(private val mAsyncTaskDao: BoxDao) : AsyncTask<Box, Void, Void>() { override fun doInBackground(vararg params: Box): Void? { mAsyncTaskDao.insert(params[0]) return null } } }
Even though this compiles, it might not be the best way to go about doing this. If anyone has any input on the structure of the above code, feel free to share your input.
val tst = Test.getBla()
It probably says you're trying to call getBla()
on Test.Companion
, which means you're trying to call it as a static method (Java).
abstract class Test {
companion object {
fun getBla(): Test? = ...
But you're not trying to do that, so you should probably instantiate the class you're calling your method on. It's an abstract class, so you'll need an anonymous implementation of it.
fun main(args: Array<String>) {
val test = object: Test() {}
val bla = test?.getBla()
bla?.shout()
}
Technically you also don't need fun getBla()
because you can just use a property with private setter.
var bla: Test? = null
private set
Now you can just access it as
val bla = test.bla
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.