Strange initializing of fields in Fragments / XML

I have a very simple fragment on a swipe-tabbed App (AppCompatActivity).
It contains 1 Switch ‘swSplash’ an 1 TextView ‘txSplash’ both declared in frag_setting.XML:

This one works fine: WATCHOUT!! txSplash does NOT need to be defined!

class frSetting : Fragment() {
  lateinit var swSplash : Switch
  override fun onCreate(savInsState: Bundle?)  { super.onCreate(savInsState) }
  override fun onAttach(context: Context?)     { super.onAttach(context) }
  override fun onDetach()                      { super.onDetach() }
  override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                            savInsState: Bundle?): View? {
     thisView = inflater!!.inflate(R.layout.frag_setting, container, false)
     swSplash =thisView.findViewById<View>(R.id.swSplash) as Switch
     swSplash.setOnCheckedChangeListener { _, _ -> reportSplash() }
     return thisView
  }
  fun reportSplash() {   // This one WORKS!
     txSplash.setText("Splash "+(if (swSplash.isChecked) "" else "not ")+"shown.")
  }   // WATCHOUT!! txSplash does NOT need to be defined (besides XML)! 
}

This one works too: WATCHOUT!! Neither swSplash nor txSplash are defined!

class frSetting : Fragment() {
     ---> NO lateinit var swSplash 
  // same ...  override onCreate/onAttach/onDetach  ... super.xxx ...
  // same ...  override fun onCreateView( ... 
  // same ...   thisView = inflater... 
     (thisView.findViewById<View>(R.id.swSplash) as Switch)
           .setOnCheckedChangeListener { _, _ -> reportSplash() }
     return thisView
  }
  fun reportSplash() {   // This one WORKS!
     txSplash.setText("Splash "+(if (swSplash.isChecked) "" else "not ")+"shown.")
  }   // WATCHOUT!! Neither swSplash nor txSplash are defined! 
}

But this one does NOT work: WATCHOUT!! Neither swSplash nor txSplash are defined!

class frSetting : Fragment() {
     ---> NO lateinit var swSplash 
  // same ...  override onCreate/onAttach/onDetach  ... super.xxx ...
  // same ...  override fun onCreateView( ... 
  // same ...   thisView = inflater... 
     swSplash.setOnCheckedChangeListener { _, _ -> reportSplash() }
       // Compiler ok, but runtimerror "lateinit not initialized"
     return thisView
  }
  fun reportSplash() {   // This would work!
     txSplash.setText("Splash "+(if (swSplash.isChecked) "" else "not ")+"shown.")
  }   // WATCHOUT!! Both are not defined, but txSplash=OK whereas swSplash=BAD! 
}

Neither does NOT work:

class frSetting : Fragment() {
  // same ...  override onCreate/onAttach/onDetach  ... super.xxx ...
  // same ...  override fun onCreateView( ... 
  // same ...   thisView = inflater... 
     (thisView.findViewById<View>(R.id.swSplash) as Switch) 
         .setOnCheckedChangeListener { _, _ -> reportSplash() } // here ok!
     // Try to adjust the text: (Compiler ok, )
     reportSplash()   // but runtimerror "setText() on a null object reference"
     return thisView
  }
  fun reportSplash() {   // This would work!
     txSplash.setText("Splash "+(if (swSplash.isChecked) "" else "not ")+"shown.")
  }   // WATCHOUT!!  same Function ok in onClickListener, but bad in onCreate 
}

So, some Questions:
. Where does Kotlin define the fields?
. When are they initialized?
. And how (in ‘onCreate()’) or where can I use them (without defining Lateinit and findingByView)?
. Where do I call reportSplash() as early as possible? (is there a ‘afterCreated()’?)

As there was no answer: I solved the Problem.
Helpful was: Android Fragment Lifecycle | DigitalOcean

From now on I will do most of my setting (not in onCreateView(), but) in:

import kotlinx.android.synthetic.main.frag_setting.*
override fun onViewCreated(v: View?, savedInstanceState: Bundle?) { 
// do your initialisation: eg.
}

By import are all fields form the View availabe as var.

So the complet code now is:

import kotlinx.android.synthetic.main.frSetting.*
class frSetting : Fragment() {
  override fun onCreate(savInsState: Bundle?)  { super.onCreate(savInsState) }
  override fun onAttach(context: Context?)     { super.onAttach(context) }
  override fun onDetach()                      { super.onDetach() }
  override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, 
                            savInsState: Bundle?): View? {
     return inflater!!.inflate(R.layout.frag_setting, container, false)
  }
  override fun onViewCreated(v: View?, savedInstanceState: Bundle?) { 
     swSplash.setOnCheckedChangeListener { _, _ -> reportSplash() }
     reportSplash() 
  }
  fun reportSplash(){ txSplash.setText("Splash % shown".format(
                                       if (swSplash.isChecked) "" else "not ")) }
 }

So all works neat and without additional definitions.

1 Like