0

I'm developing an app with fragments and I want to use a value from "strings.xml" in MainActivity.kt. These are the names of the tabs. But, if I do this:

private var title: String = getText(R.string.title).toString()

I get this error when I run the code:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference

If I do:

private var title = getText(R.string.title)

I also get the error and if I do:

private var title = R.string.title

I get an integer. How can I get the atual text I have in <string name="title">Start</string>?

  • Where are you calling `getText`? Sounds like you might be doing so outside the time when the fragment is actually attached to its activity, resulting in a null context. – dominicoder Mar 09 '23 at 16:25

2 Answers2

0

You should use getString(), and the function getString (as well as getText) requires your activity to be instantiated.

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var title = getString(R.string.title)
Pavel B.
  • 805
  • 10
  • 13
0

You need to be careful assigning top-level variables in things like Activities and Fragments with expressions that require a Context. They don't have one at construction time, the system provides that later - that's how you end up seeing this kind of error (in your case, it's trying to call getResources() on something that should be a Context, but it's actually null).

A fragment's Context has been attached by the time it enters the CREATED state, so it's safe to access it in onCreate or later. So you can make your top-level variable lateinit (deferring assignment) and set the value on it later:

// define the variable without a value - you need to set a value before this is read!
private lateinit var title: String

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    // assign the value when you can
    title = getText(R.string.title).toString()
}

Or you could use a lazy delegate, which will set the value the first time the variable is accessed, by running a setter function:

private val title: String by lazy {
    getText(R.string.title).toString()
}

This will fail if the function is called before the Context is available too, so in both situations you have to be able to guarantee nothing will try to read from it too early. The lazy is arguably neater (no separate assignment) but it does make the value read-only, instead of a var - that's probably fine in this situation!

Also if you specifically want a String instead of a CharSequence, just call getString instead of getText

cactustictacs
  • 17,935
  • 2
  • 14
  • 25