Alright, so I have a fragment that displays user account information.
The way this works is it issues a request that may or may not touch the server, depending on what information is already cached.
When the information is available, there's a callback in which the fragment will update its textfields.
At that point, however, the UI needs be refreshed, so I'd like to issue some kind of invalidate
...
Except that does perfectly nothing.
First, I noticed that this.view
returns null
. So rather than rely on that, I store the view I create in onCreateView
explicitly.
Then after I updated the textfields, I call fragmentView.postInvalidate()
... which does nothing.
I also tried doAsync { uiThread { fragmentView.invalidate() } }
... which also does nothing.
Then I found this answer and tried
val fragment = this
doAsync { uiThread {
activity!!.supportFragmentManager.beginTransaction().detach(fragment).commit()
activity!!.supportFragmentManager.beginTransaction().attach(fragment).commit()
}}
... which is even WORSE than not doing anything, because the other two ways will at least update the view if you switch to a different fragment and back, whereas this will perpetually refuse to display any useful information.
So maybe I can "cheat" by delaying the call to super::setUserVisibleHint
until after I updated the values ... no, I can't.
What I can do, though, is I can force a redraw of the ui by toasting something. So that's what I am currently doing. But still, that can't be the solution.
How do I get a proper ui refresh?
Oh, and this is an android.support.v4.app.Fragment
and I'm using an android.support.v4.app.FragmentStatePagerAdapter
to switch between fragments, if that matters.
Full fragment code:
class AccountFragment : Fragment() {
lateinit var fragmentView: View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
val view = inflater.inflate(R.layout.fragment_account, container, false)
/*for some reason [this.view] remains null when we later try to use it, so we're explicitly storing a reference*/
fragmentView = view
return view
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
if(isVisibleToUser)setAccountInformation()
super.setUserVisibleHint(isVisibleToUser)
}
private fun setAccountInformation(){
val um = DataConfig.getUserManager()
val au = um.getActiveUser()
um.getUserInfo(au, Callback(
onResponse = {when(it){
is SuccessfulAccountGetResponse -> {
val info = it.result
usernameText.text = info.name
uuidText.text = info.uuid
adminText.text = if(info.isAdmin) "YES" else "NO"
createdText.text = info.created.toString()
lastLoginText.text = info.lastLogin?.toString() ?: "-"
//now actually force the new information to show up
refreshUI()
}
else -> doAsync { uiThread{ activity?.longToast("could not get information") } }
}},
onError = {doAsync { uiThread { activity?.longToast("error: $it") } }}
))
}
/** forces a refresh, making changes visible*/
private fun refreshUI(){
/*hack: force a redraw by toasting */
doAsync { uiThread { activity?.toast("updating values") } }
//THIS does absolutely nothing: //TODO: figure out why
// fragmentView.postInvalidate()
}
}