Skip to content
This repository has been archived by the owner on Sep 12, 2019. It is now read-only.

Bind view in retained Fragment #5

Open
damianpetla opened this issue Dec 21, 2014 · 9 comments · May be fixed by #7
Open

Bind view in retained Fragment #5

damianpetla opened this issue Dec 21, 2014 · 9 comments · May be fixed by #7

Comments

@damianpetla
Copy link

@JakeWharton I was wondering if you tried to handle binding views in retained Fragments?

I will explain the problem to everyone else:
When you set your fragment retained calling setRetainInstance(true) view properties once created are kept in memory after fragment layout is re-created e.g. screen orientation changes. It means that after orientation change properties points to the view from the old invalid layout reference.
With java ButterKnife you have to call inject() in respective fragment method callback. In case this library injection is done automatically whenever view is used for the first time.

@JakeWharton
Copy link
Owner

I don't use fragments, but I understand the requirement. ButterKnife has reset(Object) for this purpose.

@damianpetla
Copy link
Author

ButterKnife works great but KotterKnife does not have such functionality. So is there a chance that you will try to take care of that issue? If not, I will try myself but I am still learning Kotlin so it may take some time :)

@MichaelRocks MichaelRocks linked a pull request Jan 8, 2015 that will close this issue
@MichaelRocks
Copy link

@JakeWharton, could you please merge my pull request that fixes this issue?

@clynamen
Copy link

Wouldn't be better to have a single object that manages all the lazy values in the fragment that is updated in onCreateView() in order to invalidate all the cached values? I will write and submit a pull request in the future

@svenjacobs
Copy link

I have the same issue with Fragments. Also happens when setRetainInstance(true) was not set.
Let's say a Fragment is detached and then reattached. The same Fragment instance will be reused however it will go through onCreateView() and onViewCreated() again. So the Views are new instances but the properties still point to the old View instances.

private val textView: TextView by bindView(R.id.text)

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) =
        inflater.inflate(R.layout.fragment_main, container, false)

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

    // Ooops, won't work when the Fragment is reattached 
    // because an old instance is accessed    
    textView.setText("This is a test")
}

@pftbest
Copy link

pftbest commented Jul 20, 2015

So by this logic every use of lazy property in activity or fragment is doomed to fail?
Is it safe to do something like this:

val category: String by lazy { getIntent().getStringExtra(EXTRA_CATEGORY) }

@svenjacobs
Copy link

So by this logic every use of lazy property in activity or fragment is doomed to fail?

Well, if it's a value that might change and needs to be recalculated on every use of the Activity/Fragment instance I would say yes, lazy cannot be used then.

@damien5314
Copy link

I'm also having this issue today with my FragmentPagerAdapter. After navigating far enough away from a fragment in a ViewPager, the FragmentPagerAdapter will destroy the view of that Fragment, but the Fragment itself and everything to which it holds a reference will remain in memory. Upon recreation of the Fragment's view, the view bindings are not reset.

If anyone has come up with a good workaround for this I'd appreciate your input 👍

EDIT: Nevermind, I just merged the PR from @MichaelRocks into my project, and it works perfectly. Thanks!

@rabidaudio
Copy link

Another option is to have methods like

@Suppress("UNCHECKED_CAST")
fun <V: View> SupportFragment.bindViewNoCache(@IdRes id: Int): ReadOnlyProperty<SupportFragment, V> {
    return object: ReadOnlyProperty<SupportFragment, V> {
        override fun getValue(thisRef: SupportFragment, property: KProperty<*>): V {
            return thisRef.view!!.findViewById(id) as V
        }
    }
}
val myView: TextView by bindViewNoCache(R.id.my_view_id)

I realize this is the same as

val myView get() = view!!.findViewById(R.id.my_view_id) as TextView

but it is slightly shorter and allows consistent access syntax with bindView

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants