https://kotlinlang.org logo
#compose
Title
# compose
f

Fudge

07/29/2020, 7:07 PM
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

jim

07/29/2020, 7:27 PM
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

Fudge

07/29/2020, 7:33 PM
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

Ian Lake

07/29/2020, 7:50 PM
Sounds like you've identified the state you need to expose 🙃
😍 1
👍 1
👆 1
2
l

Leland Richardson [G]

07/29/2020, 7:51 PM
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

jim

07/29/2020, 7:52 PM
@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

Timo Drick

07/29/2020, 8:33 PM
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

Ian Lake

07/29/2020, 10:00 PM
You might consider a bit more layering (ala a repository you can mock/fake) vs doing network requests right in your composable.
j

jim

07/29/2020, 10:05 PM
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

Leland Richardson [G]

07/29/2020, 11:00 PM
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

jim

07/29/2020, 11:10 PM
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

Leland Richardson [G]

07/29/2020, 11:15 PM
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

jim

07/29/2020, 11:16 PM
😂 like I said, a contentious topic.
😛 1
i

Ian Lake

07/30/2020, 1:04 AM
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

Timo Drick

07/30/2020, 10:41 AM
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

caelum19

07/30/2020, 10:43 AM
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

Timo Drick

07/30/2020, 10:48 AM
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

gildor

07/30/2020, 11:12 AM
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

Timo Drick

07/30/2020, 11:18 AM
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

gildor

07/30/2020, 11:28 AM
I don’t think that checking animation is really a thing for preview, more it could show different states of this UI