Why is `resources()` marked as internal in <androi...
# compose
s
Why is
resources()
marked as internal in androidx.compose.ui.res ? I am in a place where I need to decide on a string to be used inside my ViewModel. As described here, I am only exposing the StringRes Int from there, and I need to then resolve that string inside my composable. Specifically, I am outside of a composable context since I am resolving it inside a lambda, so I can’t just use the
stringResource()
function which uses this function internally. So it turns out I need to do what
stringResource()
does interally myself, which is
Copy code
LocalConfiguration.current
return LocalContext.current.resources
So that I make sure I read LocalConfig in order to make sure I do not grab stale data.
resources()
already exists and does this exact thing, but it’s marked as internal, shouldn’t that just be a public function?
d
Coming from a decade of experience doing Android. I highly suggest not allowing string IDs be used in the ViewModel or any other layer above it either.
s
Yeah maybe that's what I should be doing regardless. Lemme tell you why I'm doing this ATM. Backend returns a list of options for smth. On the client, we are gonna add another "Not Sure" option. So I create another object of that type inside my VM, and since that model already has a "displayName" in it, I give it one inside the VM just as I create it, for the UI then to render. What I absolutely don't want is for the UI to contain this sort of logic. But it's true that what I can do is take that object, make it part of a sealed hierarchy, and make another subclass of it which is named NotSureItem or smth. Then have the VM create it, but don't specify what the displayName will be. And on the UI, if I want to render that item, simply decide there and then to use that string. This will make it so that the VM decides on when to add this item, and the UI decides on what display name it will have, kinda splitting the logic of this item in two places, but maybe that's not that bad 🤔
But with all that said, the more generic need to potentially resolve a string inside a non-composable lambda still stands, in which case to be able to just get a reference to
Resources
the same way that
resources()
does would be very valuable. I wrote this report to see what they think.
m
It is perfectly fine to add a string to viewmodel, you just SHOULDN’T resolve it there. In your case, just create a layer of indirection to build the string lazily
d
It is perfectly fine to add a string to viewmodel, you just SHOULDN’T resolve it there. In your case, just create a layer of indirection to build the string lazily
And how does this work when Unit testing the ViewModel?
m
what is the problem? It’s just a primitive id. Can you elaborate ?
d
It’s the first step towards a slippery slope. Think of the situation where your String ID references a string template that then requires arguments and further composition. Ideally the ViewModel should hold the data derived from your data, domain, and service layers. How that data is represented is the part of the View Controller / View / Composable layer. https://kotlinlang.slack.com/archives/CJLTWPH7S/p1679559009844329?thread_ts=1679524819.015979&amp;cid=CJLTWPH7S This ☝️ is exactly the line of reasoning that aids in solving the problem.
Once you get into a situation where the ViewModel layer needs to compose multiple strings IDs you find the need for resolution. Resolution in a ViewModel is going to result in added infrastructure. That in turn adds in complexity, which reduces maintainability.
That said, this example here: https://developer.android.com/topic/architecture/domain-layer#use-cases-kotlin Demonstrates a possible approach to doing string manipulation in the ViewModel layer.
m
in complex applications you need to model what are you going to show in a given Text composable. Some situations you might show a int resource. Others a string from the server. Others a plural resource. Others a string with replacements, or a html string, all within the same composable. And it is the viewModel that decides what to show when. There is nothing wrong in creating a layer of indirection around those strings that tell you how to build it. The string resolution will only happen in the view layer obviously. you need the appropriate context to resolve the string. There is no different between THIS and work around it by creating multiple sealed abstractions for those cases i talked about, is there ?
d
This is not a hill I am willing to die on. I have offered my thoughts. It’s up to you to make the best long term decision for your project.
m
I am happy to be persuaded based on arguments. You simply stated it as being a ‘slippery slope’ and gave no arguments
d
Yes, because I am not arguing lol
m
ok then! nice
thanks for the fb