androidkotlin

Why do I get the error java.lang.IllegalStateException: instance not initialized?


I get the error

java.lang.IllegalStateException: instance not initialized

you can test it at https://www.dropbox.com/s/gxeok1fyttsl54u/MyMirror.zip?dl=0

It seems that the code operator fun getValue(thisRef: Any?, property: KProperty<*>)... in UIApp causes the error.

But the code is from a sample code, I hardly don't change, you can see source code at https://github.com/antoniolg/Kotlin-for-Android-Developers/blob/master/app/src/main/java/com/antonioleiva/weatherapp/ui/App.kt

and

https://github.com/antoniolg/Kotlin-for-Android-Developers/blob/master/app/src/main/java/com/antonioleiva/weatherapp/extensions/DelegatesExtensions.kt

Why?

java.lang.RuntimeException: Unable to start activity ComponentInfo{info.dodata.mirror/ui.UIMain}: java.lang.IllegalStateException: instance not initialized
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2107)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2132)
at android.app.ActivityThread.access$700(ActivityThread.java:140)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1238)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4918)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.IllegalStateException: instance not initialized
at ui.UIApp$NotNullSingleValueVar.getValue(UIApp.kt:23)
at ui.UIApp$Companion.getInstance(UIApp.kt)
at dal.DBSettingHelper.<init>(DBSettingHelper.kt:9)
at ui.UIMain.onCreate(UIMain.kt:14)
at android.app.Activity.performCreate(Activity.java:5185)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2071)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2132)?
at android.app.ActivityThread.access$700(ActivityThread.java:140)?
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1238)?
at android.os.Handler.dispatchMessage(Handler.java:99)?
at android.os.Looper.loop(Looper.java:137)?
at android.app.ActivityThread.main(ActivityThread.java:4918)?
at java.lang.reflect.Method.invokeNative(Native Method)?
at java.lang.reflect.Method.invoke(Method.java:511)?
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)?
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)?
at dalvik.system.NativeStart.main(Native Method)?

UIMain

package ui
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import dal.DBSettingHelper
import info.dodata.mirror.R


class UIMain : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.layout_main)
        var ss= DBSettingHelper();
    }

}

DBSettingHelper

package dal

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import org.jetbrains.anko.db.*
import ui.UIApp

object DBSettingTable {
    val TableNAME = "SettingTable"

    val _ID = "_id"
    val Name = "name"
    val CreatedDate = "createdDate"
    val Description="description"
}


class DBSettingHelper(mContext: Context = UIApp.instance) : ManagedSQLiteOpenHelper(
        mContext,
        DB_NAME,
        null,
        DB_VERSION) {

    companion object {
        val DB_NAME = "setting.db"
        val DB_VERSION = 1
        val instance by lazy { DBSettingHelper() }
    }

    override fun onCreate(db: SQLiteDatabase) {
        db.createTable( DBSettingTable.TableNAME , true,
                DBSettingTable._ID to INTEGER + PRIMARY_KEY,
                DBSettingTable.Name to TEXT,
                DBSettingTable.CreatedDate to INTEGER,
                DBSettingTable.Description to TEXT
        )
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.dropTable(DBSettingTable.TableNAME, true)
        onCreate(db)
    }

}

UIApp

package ui

import android.app.Application
import kotlin.reflect.KProperty

class UIApp : Application() {

    companion object {
        var instance: UIApp by NotNullSingleValueVar()
    }

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    class NotNullSingleValueVar<T> {

        private var value: T? = null

        operator fun getValue(thisRef: Any?, property: KProperty<*>): T =
                value ?: throw IllegalStateException("${property.name} not initialized")

        operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
            this.value = if (this.value == null) value
            else throw IllegalStateException("${property.name} already initialized")
        }
    }

Solution

  • onCreate function in UIApp class is never called and thus an instance of UIApp is never initialized. This is happening because you didn't add UIApp class to AndroidManifest and because of that your app did not realize that you have your custom Application class in a project.

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="info.dodata.mirror">
    
        <application
            <!--Add line bellow to your manifest file and app will work just fine-->
            android:name="ui.UIApp"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
    
    
            <activity android:name="ui.UIMain">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
        </application>
    
    </manifest>