20

I have the following Kotlin class on Android:

class ThisApplication: Application() {

    lateinit var network: INetwork

    override fun onCreate() {

        super.onCreate()

        network = Network()
    }
}

Now, any external class can get the INetwork reference by simply doing:

application.network

However, that also makes it possible for an external class to overwrite that value:

application.network = myNewNetworkReference

I want to avoid the second option. Unfortunately, I can't make the field val because its initialization needs to happen inside the onCreate callback.

I also thought about making the field private and exposing it through a function, like this:

private lateinit var network: INetwork
fun getNetwork() = network

However, whoever calls getNetwork() can still assign a new value to it, like so:

application.getNetwork() = myNewNetworkReference

How can I make the network field to be read-only by external classes? Or even better, is there a way to make it val even though I can't initialize it inside a constructor?

4

3 回答 3

37

To restrict the access from the external classes, you can change the visibility of accessors. For your case, you need private setter and public getter with lateinit modifier:

lateinit var network: INetwork
    private set

Or a read-only lazy property:

val network: INetwork by lazy { Network() }  //you can access private property here, eg. applicationContext

There are some misunderstanding from you about this code:

private lateinit var network: INetwork
fun getNetwork() = network

Kotlin is pass-by-value as what Java does. So, application.getNetwork() = myNewNetworkReference is not a valid statement. We cannot assign value to the return value of a function.

于 2017-08-20T03:35:16.193 回答
12

You can modify the visibility of the getters/setters independantly from the actual variable:

lateinit var network: INetwork
    private set
于 2017-08-20T00:48:21.170 回答
2

Would val network: INetwork by lazy { ... } work for your scenario?

The lambda expression gets called with the first reference to the field network. Obviously, this isn't the same as deferring initialization to the OnCreate method, but it is a way to make it val without having to initialize it in the constructor.

There are other delegation choices as well. The Kotlin documentation is worth checking out.

于 2017-08-20T00:15:50.687 回答