What was the function to check if we are currently...
# compose
f
What was the function to check if we are currently in a
@Preview
? I remember there was one but I can't find it. Something like
Something.isInPreview()
🤔 1
Did I dream it... no way...
j
The very concept of such a function makes me very nervous. It makes me think your widget is not sufficiently isolated / is not a function of its parameters. Why do you want to know if you're in a preview?
2
f
Because I want to show things that are not shown with the default state and I can't be bothered to accept all of the state of the component in its parameters
i
Sounds like you've identified the state you need to expose 🙃
😍 1
👍 1
👆 1
2
l
it might be a smell but i dunno i could see this being useful if we are still going to not let preview do everything like network requests
it not being able to do network requests makes me very very sad fwiw
j
@Fudge If you don't want to accept all the state as separate parameters, you can consider a single hosited state object that maintains the internal state of your widget.
You can even provide a remembered default parameter, so in most cases, when users don't care to provide/hoist such a state, the widget just does the default thing
Copy code
@Composable
fun myWidget(myState: WidgetState = remember { MyWidgetDefaultStateImpl() }) {
   // Use/update mystate here
}
t
As long as network requests (background thread) are not possible in Previews they are very limited. But i hope this get solved in the future. Or am i wrong?
i
You might consider a bit more layering (ala a repository you can mock/fake) vs doing network requests right in your composable.
j
Yeah, it might be a controversial opinion and is not necessarily the official opinion of the team nor held by everyone on the team, but I personally think that
@Preview
not supporting network requests actually ends up pushing developers to write better widgets (specifically, by discouraging widgets which are sideways loading data). So among other reasons that widgets are sandboxed, this does not make me sad.
Keep in mind that as @Ian Lake mentioned, you can still accept a parameter (with a remembered default value) that provides a default network layer, and can be overridden/mocked when calling from preview. Not that I recommend this approach (I still think sideways data loading is bad) but ¯\_(ツ)_/¯.
l
i just think the Image component should work. “sideways data loading” for this is not a smell IMO
the industry works with images through URLs. its just how it is
if an API sends me a URL, i want to turn that into an image with very little ceremony
and if the preview doesn’t do that for me, its utility dramatically decreases
j
There is some convenience to being able to think of an image as a URL, but the reality starts to get more complex. What happens when you're out of cellular range? What happens when the hosing server has gone down permanently? What happens when your parent needs to be able to route the request through a firewall proxy because you're operating in a secure environment? These edge cases can all be reasonably handled by a parent when the parent is responsible for loading the data and passing it to the child. Not to mention unit testing. And heck, what if the image doesn't even come from the network and instead you want to load it from your Android resources or from a local cache? Assuming you don't want to overload the API ala
@UnionType
, you need to choose a parameter type, and from an API perspective, accepting the non-string-based type starts to look pretty appealing. And then the question becomes, how easy/hard does it need to be to load an image? Can it be made as simple as a call to a load function? Is
Image(url="<https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png>")
really much better than
Image(img=network.load("<https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png>"))
? Especially when it opens so many other doors with regards to where that image could have come from.
l
i can provide a more complete answer but i really should get back to my slides 😛 but my short answer to is it “really much better?” is “yes, and i think it can open just as many doors”
j
😂 like I said, a contentious topic.
😛 1
i
Of course, that just means your image loader is using some global Singleton / defaults to configure how it loads things from the network (which is actually what Picasso, Coil, etc. all actually do under the hood when you don't use their explicit load calls that specify those).
t
It is not just about images. You should be able to do background work in the preview. Of course a simple widget could be mocked with some local data. But when you create compositions of widgets and than the complete app screen that is not possible anymore because you are using URLs. For testing of course you could use URLs to local files but still you need to load them asynchronously. And also maybe you want to test if you Image widget can show a progress indicator and than switch to the image after loading.
c
I suppose the standard of the UI making separate network requests for images is much more acceptable when they are already dependent on the network, like how web pages entirely rely on network access and if an API returns urls then that api needs network access anyway. Maybe image urls should just never be in string literals?
t
I am developing now a Compose app for about 6 month and i cannot use the preview most of the time because i am doing asynchronous loading all the time. It is not done by the UI but the UI relays on some worker classes. For me it would be ok to use an other component for data loading in preview. But there must be a way doing this things asynchronously. Why it is a problem just support normal threads?
g
oh, threads is definietely not what I would like to see in preview and even components What kind asyncronous loading are you doing in you components?
t
It is indeed 90% image loading. But also loading configurations and than the UI shows loading spinner and do a crossfade to a error screen or showing the result. Ok lets assume i would inject the image loading by an ambient provider and for preview i than use a different provider which can simulate loading without using a background thread. How could i do this? Are animations working? Maybe we could at least use coroutines to do this simulation?
But at the end. Why do i have to have more code just to get the preview working. When it is very easy to test it on the device? And currently building the preview takes longer than compile and deploy to a emulator or device 😄
So as long as there are such limitations. I can only use the preview to check smaller widgets and get them working. Maybe when animations work in preview this would also be helpful.
g
I don’t think that checking animation is really a thing for preview, more it could show different states of this UI