Search code examples
androidkotlinandroid-lifecycle

Why app crash when enter in landscape mode? kotlin.UninitializedPropertyAccessException: lateinit property has not been initialized


If when the app switch to landscape mode the method onCreate() is recalled, why do I receive this error: kotlin.UninitializedPropertyAccessException: lateinit property has not been initialized only if the app enters in landscape mode but not in the portrait mode?

It sounds me that I need to clean some resources in onPause() or onStop() first to recall the onCreate()

My main activity:

class MainActivity : AppCompatActivity() {

companion object {
    const val FILENAME = "file.txt"
    const val TAG = "APP"
}

private lateinit var binding: ActivityMainBinding
private lateinit var adapter: AdapterComuni

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    loadData()
    setUIControl()
}

private fun loadData() {
    val reader = assets.open(FILENAME).bufferedReader()
    CoroutineScope(Dispatchers.IO).launch {
        val listaComuni = ListaComuni()
        reader.useLines { lines ->
            lines.forEach {
                listaComuni.add(Comune(it))
            }
            launch(Dispatchers.Default) {
                listaComuni.listaComuni.sortBy { it.comune }
                launch(Dispatchers.Main) {
                    Log.d(TAG, "LETTO!")
                    adapter = AdapterComuni(
                        listaComuni
                    )
                    val layoutManager = LinearLayoutManager(this@MainActivity)
                    binding.rvComuni.layoutManager = layoutManager
                    binding.rvComuni.adapter = adapter
                }
            }
        }
    }
}

private fun setUIControl() {
    binding.svComuni.setOnQueryTextListener(TextChangeListener())
}

inner class TextChangeListener: SearchView.OnQueryTextListener {
    override fun onQueryTextSubmit(p0: String?): Boolean {
        return findAllSimilarCountry(p0)
    }

    override fun onQueryTextChange(p0: String?): Boolean {
        return findAllSimilarCountry(p0)
    }

}

private fun findAllSimilarCountry(p0: String?): Boolean {
    adapter.getFilter(binding.spnFilter.selectedItem.toString(), this).filter(p0)
    return true
}

}

The full error:

kotlin.UninitializedPropertyAccessException: lateinit property adapter has not been initialized
    at com.user.app.MainActivity.findAllSimilarCountry(MainActivity.kt:73)
    at com.user.app.MainActivity.access$findAllSimilarCountry(MainActivity.kt:14)
    at com.user.app.MainActivity$TextChangeListener.onQueryTextChange(MainActivity.kt:67)
    at android.widget.SearchView.onTextChanged(SearchView.java:1261)
    at android.widget.SearchView.access$2100(SearchView.java:99)
    at android.widget.SearchView$10.onTextChanged(SearchView.java:1789)
    at android.widget.TextView.sendOnTextChanged(TextView.java:10069)
    at android.widget.TextView.setText(TextView.java:5938)
    at android.widget.TextView.setText(TextView.java:5776)
    at android.widget.EditText.setText(EditText.java:122)
    at android.widget.TextView.setText(TextView.java:5733)
    at android.widget.TextView.onRestoreInstanceState(TextView.java:5601)
    at android.view.View.dispatchRestoreInstanceState(View.java:18820)
    at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3883)
    at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3883)
    at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3883)
    at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3883)
    at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3883)
    at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3883)
    at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3883)
    at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3883)
    at android.view.View.restoreHierarchyState(View.java:18798)
    at com.android.internal.policy.PhoneWindow.restoreHierarchyState(PhoneWindow.java:2234)
    at android.app.Activity.onRestoreInstanceState(Activity.java:1210)
    at android.app.Activity.performRestoreInstanceState(Activity.java:1164)
    at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1338)
    at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3470)
    at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
    at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2199)
    at android.os.Handler.dispatchMessage(Handler.java:112)
    at android.os.Looper.loop(Looper.java:216)
    at android.app.ActivityThread.main(ActivityThread.java:7625)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)

MainActivity.kt:73 is the line: adapter.getFilter(binding.spnFilter.selectedItem.toString(), this).filter(p0)


Solution

  • The adaper is initialized only after the data is loaded (asynchronously) but setUIControl() is called before (while the data is still being loaded).

    setUIControl() sets a TextChangeListener which accesses the adapter variable when onQueryTextChange is called. When the search field is populated and the screen is rotated, Android restores the search field (onRestoreInstanceState) and thus triggers onQueryTextChange.

    The solution is easy, just call setUIControl() after the RecyclerView is fully initialized (after the binding.rvComuni.adapter).