Im inside a suspending function in my viewmodel VM...
# android-architecture
a
Im inside a suspending function in my viewmodel VM, but i need to make an operation with my activity and wait for the result in my VM. How would you approach this ? My initial approach was a sharedFlow inside my VM which is observed by the Activity, which triggers the operation in the Activity. Then i send the result to a Channel and in my VM i was waiting to receive sth on that channel. Felt quiet complicated. Also i think the receive method was not waiting untill sth was sent to the channel
j
I think it is easier to just call a ViewModel function when the activity result callback is invoked which will do the same that your ViewModel observer does
👍 1
a
i see, thats also my current idea. • VM triggers Activity operation via effect (SharedFlow) • Activity on Result triggers another event / intent in the VM • Downside i would need the information, which operation needs to be triggered in the VM after receiving the result from the Activity. so i can continue my operation in the VM, where i left of
For now i have a simple solution implemented, where i just keep a reference of the activity in my Singleton Service class. I set the activity null in onStop and I make sure i dont pass it into any longer running operation.
u
What do you need? Most of the time application level Context is sufficient and that can be injected
j
I missed your comment
I don't know if you need the activity context, btw if you need it, use ActivityComponent with Hilt so you don't need to do that workaround
Sample with FragmentComponent
a
But my Viewmodel should be in a higher scope and so it shouldnt know anything about the activity imho. So i also shouldnt inject sth there which gets the activity context injected imho
j
you can inject it into the fragment directly if you want
a
yeah i guess there is no other way then the ping pong between fragment and viewmodel
thx for your feedback 👍
j
I hate that ping pong so I directly navigate from fragment instead of fragment calling a ViewModel function which emits an event that the fragment observes
I see no benefits with that ping pong in terms of testability or scaling, just overcomplicating a simple thing
a
yeah i see your point, i think my only motivation to go through vm is so i can in the logs follow what events happened and what view state or effects came from it
j
yeah, it depends to the situation too. Some time you need to do something before navigating and in that situations you need that the ViewModel do something and emit an event when it is finished
a
in my current project i saw today a nice idea, which blew my mind. i didnt test yet it works but theoreticly it could i think. So in the VM there was a class injected, which was activity scoped (actually im surprised there is no vm scope in dagger, then it wouldnt be alloowed as its a higher scope). This injected class was a NavigationClass, therefore it needed the activity. Now the idea is to have this class Activity scoped, but inject the Activity not directly but a Provider<Activity>. So this Provider will always return the scoped single instance of the Activity when u call get on the Rrovider, but as soon as the Activity is recreated the Dagger Component holding this Activity is also destroyed an recreated, so when the NavigationClass is calling the Rrovider again it should again get the new Activity instance.
j
I think you want ActivityRetainedComponent
🤩 2
a
oh wow they solved that problem already awesome thx 🙏
👍 1
just saw in the documentation that apparently u cant get the activity in that scope https://dagger.dev/hilt/components
j
Maybe you can just use ActivityComponent
The navigation graph should be attached to the navhost in the activity
I think @zhuinden talked about this but with dagger vanilla
a
yeah i think im again keen on trying my idea about Provider<Activity> inside an ActivityComponent scoped class, i will report if it worked as i imagine it
z
as long as you can enqueue navigation commands, which you can, you can forward navigation commands from VM to Activity
a
thats also a really nice idea thx 👌
just in my use case i need to actually pass the activity to a library (spotify), which is internaly using it to start their login activity
just made a quick test with my provider idea, unfortunately it is still providing the old activity after an orientation change, which is a bit against how i thought Dagger works, i thought the ActivityComponent which holds the instance of the activity scoped instances gets destroyed on a configuration change