Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin Android extensions and retained fragment

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?

like image 708
Lamorak Avatar asked Jul 02 '15 14:07

Lamorak


2 Answers

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.

like image 63
Lamorak Avatar answered Sep 17 '22 16:09

Lamorak


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.*
like image 36
yanex Avatar answered Sep 20 '22 16:09

yanex