Is there an easy way to call a function just when ...
# compose
n
Is there an easy way to call a function just when the screen is opened? 🤔 Detailed explanation: Using Navigation, I’m opening
ScreenA
which I’m using
Copy code
LaunchEffect(viewModel) {
    viewModel.loadSomeData()
}
In this screen, somewhere in the future I call
ScreenB
. But when I go back to
ScreenA
, the
loadSomeData()
is called again… Is there a way to avoid that?
l
As far as I know, and I'm not an expert, I don't think you can. Though, I would argue that it's the viewModel's responsibility to not trigger another load, not the UI's.
1
n
But the viewModel needs some kind of signal to this… This is what I want… In the old framework, it was
onCreate
method.
k
Are you getting a new instance of the ViewModel? If not (and I think you shouldn't get) then ViewModel's constructor should solve the problem
a
I agree with @Luke, this sounds like a ViewModel responsibility.
Copy code
private val alreadyLoaded = false

fun loadSomeData() {
  if (alreadyLoaded) return

  // ...
  alreadyLoaded = true
}
With activities and fragments you still get multiple onCreates too under the same circumstances and need to take the same approach if you really want it to only happen once.
☝️ 1
👍 2
n
Thanks @Adam Powell. But this solution sounds like more a workaround imho… 😕
In navigation using Fragments I can request the data loading using
onCreate
because it will not be called again when I go back to it.
n
Does viewmodels
init{}
function solves the issue?
n
No… let me put the real situation here… When I open the
Form
, I set the data. Then, when I navigate to
Country
to update the country field in
Form
the
setMyData
is called again and reset the data… 😕
Oh! And just to clarify… the original question I asked because the
myData
set to
Form
is loaded in
Home
. So, when I close the
Form
and go back to
Home
, the data is loaded again 😞
i
If you want something to be done once for the lifetime of the entire screen's existence on the back stack, that's your ViewModel for you - just use the
init
block
n
thanks @Ian Lake. But as you can see in the picture above, I can’t do it using
init
, because
HomeViewModel
load some data and it needs to pass some of this data to the
FormViewModel
just once.
For now, I did this ugly workaround which @Adam Powell mentioned… 😞
Copy code
private mydata: MyData? = null

fun setMyData(d: MyData) {
   if (myData == null) {
       mydata = d
   }
}
i
Ah, it all comes back to trying to pass whole objects rather than actually have a single source of truth. Right, yep, then everything is wrong and hard. Best of luck
n
@Ian Lake I have to say that after read your message I was a little upset, because I think you could’ve expressed your idea in a more educational way. But I want to say thank you very much (again). You made me rethink the way I was doing my implementation. Now it’s much better thanks to you 👏
i
Glad you were able to come up with a better structure 👍 Do you mind sharing what you came up with here? Maybe that would help others also avoid the same stumbling blocks
n
Sure… Basically I tried to follow the single source of truth. • My repository becomes a singleton where I’m caching the data. •
HomeViewModel
requests the data to be loaded (which is cached by the repository) • In the
FormViewModel
, in the
init
block, I asked for the data again (which cached) and call
setMyData
That was it… An elegant solution 🙂
👍 1
i
🎉 that does sound much better
s
@nglauber What about case when Process recreated, isn't Singleton cache will be cleared?