0

I have a MainApplication class declared in the AndroidManifest.xml

    <application
    android:name=".MainApplication" ...other stuffs >

that I used as a global context for my app accessible outside of any Activity or Fragment.

if I declare my MainApplication class as:

public class MainApplication extends Application {

private static MainApplication instance;

public MainApplication() {
    instance = this;
}

public static MainApplication shared() {
    return instance;
}

}

Everything is fine, and I can then use it then like this:

val c = MainApplication.shared()
return c.getSharedPreferences(prefsKey, Context.MODE_PRIVATE)

However if I declare the same class as a Kotlin class and call MainApplication.shared I get an error saying I'm calling sharedPreferences on null object

class MainApplication: Application() {
companion object {
    @JvmStatic
    val shared: MainApplication = MainApplication()
}

Is there an issue with Kotlin class declaration and singleton (SharedInstances) or Am I making an error trying to declare this class like this?

Nicolas Manzini
  • 8,379
  • 6
  • 63
  • 81

2 Answers2

1

The problem is that you are creating an instance of the Application class. It should be something like this:

class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        appContext = applicationContext
    }

    companion object {
        lateinit var appContext: Context
    }
}
Xid
  • 4,578
  • 2
  • 13
  • 35
  • you are the usual suspect... I will test your answer now :) – Nicolas Manzini Nov 27 '20 at 18:27
  • 1
    hahaha ... finally someone understands ... :D – Xid Nov 27 '20 at 18:31
  • I don't know if your answer is exactly the answer because when doing Java I don't have to override the onCreate() but the solving part I guess must be the lateinit. – Nicolas Manzini Nov 27 '20 at 18:40
  • 1
    I ended up doing class MainApplication : Application() { override fun onCreate() { super.onCreate() shared = this } companion object { lateinit var shared: MainApplication } } – Nicolas Manzini Nov 27 '20 at 18:41
  • 1
    It is that in Java you initialize the variable in the constructor like so `instance = this;` but in kotlin your are creating a new object like so `val shared: MainApplication = MainApplication()`. I just moved your code to `onCreate` as other parts of the application will be initialized only after your application object is created. – Xid Nov 27 '20 at 18:44
  • make sense I get it now :) – Nicolas Manzini Nov 27 '20 at 18:47
0

you are getting the error cause you cannot instantiate an Application object in that way. In order to get the application object you need to declare it in your AndroidManifest.xml with the android:name property

<application
    android:icon="@mipmap/ic_launcher"
    .
    .
    .
    android:name="your.package.MainApplication">

</application>

And in order to get the application inside a Fragment you can do this

val myApplication = requireActivity().application as MainApplication

Or in an Activity

val myApplication = application as MainApplication

Edit 1 If you want to have a singleton, you can create it directly in Kotlin

object Foo{
   val bar: String = "Something you want globally"
}

But never put a context related object in a static variable.

omensight
  • 90
  • 1
  • 9
  • in the manifest I have – Nicolas Manzini Nov 27 '20 at 15:38
  • @NicolasManzini Both ways are the same, I prefer the fully qualified name, but you can use that also. – omensight Nov 27 '20 at 15:41
  • actually I want to use this context outside of any fragments or Activity that is why I made this class in the first place. I refined the question after your answer. – Nicolas Manzini Nov 27 '20 at 15:42
  • If you want to use the Application as a singleton that contains itself, I discourage you to do this, because it would be an antipattern due to a memory lack. – omensight Nov 27 '20 at 15:48
  • definitely not an anti pattern. See https://stackoverflow.com/questions/708012/how-to-declare-global-variables-in-android?rq=1 . There is no memory leak, the class must be alive for as long as my app is alive. There's nothing inside this class except a reference to itself. – Nicolas Manzini Nov 27 '20 at 15:52