简体   繁体   中英

Unresolved reference to function in custom class

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.

#### EDIT

I'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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM