-1

I got a NullPointerException which appeared strange at first (or rather still does). The corresponding code is:

class Player(
    private val scope: CoroutineScope,
    private val ctx: Context
) {
    init {
        Log.d("FOO", ctx.toString())
        Log.d("FOO", ctx.cacheDir.toString())
    }
    ...
}

class MainActivity : AppCompatActivity() {
    val player = Player(lifecycleScope, this)
    ...
}

The log output is:

FOO/de.andrekr.android.box.MainActivity@90d5f8e
AndroidRuntime/Shutting down VM
AndroidRuntime/FATAL EXCEPTION: main
               Process: de.andrekr.android.box, PID: 30690
               java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{de.andrekr.android.box/de.andrekr.android.box.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.File android.content.Context.getCacheDir()' on a null object reference

Note how it prints de.andrekr.android.box.MainActivity@90d5f8e, proving that ctx is not null but then when I call getCacheDir() I get the NPE.

I found this answer that says:

But an Activity isn't a context exactly, it has access to one

So how does this work in Java terms? Activity extends Context, doesn't it? How can ctx change from being Activity to being null? Especially since it's immutable (Kotlin val)?

AndreKR
  • 32,613
  • 18
  • 106
  • 168
  • `Activity` is a `ContextWrapper`, which is just a `Context` that delegates all method calls to another `Context` instance it keeps as a field. It's that field that's null when you try to use `Context` methods in your class's field initializers; it hasn't been set yet by the system. Those particular NPEs are a little confusing at first. – Mike M. Nov 05 '22 at 05:49
  • @MikeM. OMG, you're right, I totally missed the top line of the stack trace which reads `at android.content.ContextWrapper.getCacheDir(ContextWrapper.java:273)`. It isn't *my* call that fails, but the delegation. You want to make this an answer or should I? – AndreKR Nov 05 '22 at 05:54
  • Go nuts. I don't do answers atm. Cheers! – Mike M. Nov 05 '22 at 05:54

1 Answers1

0

It turns out (thanks Mike M. for your comment) that Attempt to invoke virtual method 'java.io.File android.content.Context.getCacheDir()' doesn't refer to my ctx.cacheDir.toString() call but instead to this line from ContextWrapper:

@Override
public File getCacheDir() {
    return mBase.getCacheDir();
}

I simply had missed the top line of the stack trace which reads:

    at android.content.ContextWrapper.getCacheDir(ContextWrapper.java:273)
AndreKR
  • 32,613
  • 18
  • 106
  • 168