10

I am using Kotlin Android extensions in my project and I came across some behavior that I am unable to understand. I use this code to retain my fragment in the activity:

val fragment = fragmentManager.findFragmentByTag("hello") ?: HelloFragment()
fragmentManager.beginTransaction()
               .replace(R.id.fragment_container, fragment, "hello")
               .commit()

This is the retained Fragment:

import kotlinx.android.synthetic.hello.*

public class HelloFragment : Fragment() {
    val text = "Hello world!"

    override fun onCreate(savedInstanceState: Bundle?) {
        super<Fragment>.onCreate(savedInstanceState)
        setRetainInstance(true)
    }

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater?.inflate(R.layout.hello, container, false)
    }

    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super<Fragment>.onViewCreated(view, savedInstanceState)

        text_view.setText(text) // <- does not work when retained
    }
}

and its XML layout hello.xml:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/text_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center" />

Everything works as expected – the text_view.setText() displays Hello world! on screen on the first launch. But when you rotate the screen the text_view.setText() does not work. This is weird because text_view is not nullable and has to reffer to some view. If you remove setRetainInstance(true) and leave the fragment recreate every time this problem disappears. Any thoughts what might cause this problem?

Lamorak
  • 10,957
  • 9
  • 43
  • 57

3 Answers3

15

UPD: The issue is fixed now. You don't have to call clearFindViewByIdCache() manually anymore.

View cache is not cleared after calling onDestroyView(). There is an open issue.

For now, you can explicitly invoke clearFindViewByIdCache() in onDestroyView() to clear the cache. This method is part of the synthetic package so you have to import it

import kotlinx.android.synthetic.*
yanex
  • 1,101
  • 8
  • 10
7

I have found the answer myself. The Fragment class does not inflate the layout directly – it has property view: View? which holds it. This should be pretty obvious since it is created with onCreateView. In order to access the properties within the view you have to set the import

import kotlinx.android.synthetic.hello.view.*

and then access the properties as follows

view?.text_view?.setText(text)

Note that these properties are nullable.

Lamorak
  • 10,957
  • 9
  • 43
  • 57
  • Do we always have to use clearFindViewByIdCache() if we use import kotlinx.android.synthetic.* in our fragments??? – cesards Apr 12 '16 at 10:55
  • You shouldn't need `clearFindViewByIdCache()` anymore according to [another answer](http://stackoverflow.com/a/33150682/4584675) to this question. – Lamorak Apr 12 '16 at 11:59
7

Just to clarify. The issue is fixed now. You don't have to pass clearFindViewByIdCache() anylonger. Please see issue tracker: https://youtrack.jetbrains.com/oauth?state=%2Fissue%2FKT-8073

greenspand
  • 749
  • 2
  • 8
  • 15