How to Use String Resources In a ViewModel - Android Studio Tutorial

  Рет қаралды 40,354

Philipp Lackner

Philipp Lackner

Күн бұрын

Пікірлер: 155
@irounik
@irounik 2 жыл бұрын
Nice one! TLDR: Return resource id instead of String from ViewModel using a wrapper class, then extract the string from UI layer where context is available.
@rpitpatel1004
@rpitpatel1004 Жыл бұрын
Can you point me direction of example for better understanding?
@evanparrish4329
@evanparrish4329 2 жыл бұрын
This was impressive, Philip. Power to you for constantly improving and thanks for sharing your knowledge!
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Glad you enjoyed it!
@Internet_Ghost-GA
@Internet_Ghost-GA Жыл бұрын
I really want to become like you in coding . I am so glade to find youtuber like you who share his knowledge with us
@danju132
@danju132 2 жыл бұрын
The timing on this one is crazy, I was just trying and failing to solve this problem :D well, that problem is now solved :) you are the GOAT!
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Glad I could help!
@yuriynekhodov3158
@yuriynekhodov3158 2 жыл бұрын
If you need to show error message, you can create sealed class/interface UiEvent, add its child for every type of error in hierarchy, and then map it in UI layer with when operator and using local context. So you won't need resources in your view model or domain layer.
@prabhatpandey5077
@prabhatpandey5077 2 жыл бұрын
I was using a data class to hold either a messageStr or a messageResId and sending that as error text to my UI layer from viewmodel. The thought of using sealed class didn't occur to me. Many thanks for this helpful video.
@edgaremmanuel3197
@edgaremmanuel3197 2 жыл бұрын
I am a fluttter developer but I learn alot from this channel
@mithilmehta1501
@mithilmehta1501 Жыл бұрын
You don't know how much I have learned from you. Your tips and tricks are awesome 🙏
@andres_tomillas
@andres_tomillas 2 жыл бұрын
Wow, I've just faced that issue today, and here is your upload! The universe has heard me 😅 Thanks for your videos, you're doing a great job, keep it up!
@JordanTuffery
@JordanTuffery Жыл бұрын
Hi Philip, I just discovered your video ! Fun fact We did litteraly the same approach (even same naming sometimes) in our app last year too, And I'd like to share an improvement about this code, and it would be to add a sealed class called Args in the UiText.StringResource , which will allow you to have arguments in your string like "blabla %s". The final result would look like this : sealed class UiText { data class DynamicString(val value: String) : UiText() data class StringResource( @StringRes val resId: Int, val args: List = emptyList() ) : UiText() { sealed class Args { data class DynamicString(val value: String) : Args() data class UiTextArg(val uiText: UiText): Args() fun toString(context: Context) = when (this) { is DynamicString -> value is UiTextArg -> uiText.asString(context) } } } fun asString(context: Context): String = when (this) { is DynamicString -> value is StringResource -> context.getString( resId, *(args.map { it.toString(context) }.toTypedArray()) ) } }
@mohsenrzna8473
@mohsenrzna8473 2 жыл бұрын
Despite the code and the nice approach, it shows your commitment and love to make content on KZbin even when you got cold. Keep up the good work! ;)
@PhilippLackner
@PhilippLackner 2 жыл бұрын
I was waiting for someone to notice :D Thanks a lot man!
@clamum9648
@clamum9648 2 жыл бұрын
Philipp you absolute gigachad, you should do a video on how to do layouts/UIs with Jetpack Compose, but not like the million other tutorials out there that position a few little text fields around and change the background color. That's not useful for people trying to learn this for the first time and interested in writing an actual real-world app. So just like the positioning of different elements and putting them together to create real-world app UIs, showing different functionalities of the Modifier, etc. I haven't seen anything good like this, and even the single class on Udemy that seems to be just on layouts doesn't look very extensive and is short.
@leonawroth2516
@leonawroth2516 2 жыл бұрын
This looks really interesting. I always just passed down the resId and let the view handle the rest. But your solution looks even cleaner. I'll give it a try!
@tutorialexpress1894
@tutorialexpress1894 2 жыл бұрын
Hi phillip could you help me to understand how can use navigation components for feature multi module with arguments and DeepLinks?
@nokapr6493
@nokapr6493 2 жыл бұрын
Nice video! Just few thoughts: - Why not to use MutableState instead of Channel? What is the advantage of using Channel here? - Also DynamicString seems a bit misleading to me, since the string/text is rather fixed than dynamic (when you change device language, the text doesn't change). Would name it StringValue maybe. But overall very good video.
@legato0
@legato0 2 жыл бұрын
I was looking for an answer to this problem for a long time and finally thanks to you the problem was solved 👍👍
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Great 👍
@RexTorres
@RexTorres 2 жыл бұрын
I wish I knew this months ago!! Thanks for this, Philipp!
@TechCrack01
@TechCrack01 2 жыл бұрын
Nice trick 👌! However, with a good UiState representation, you shouldn't need to send that string text from your VM to your UI layer at first place.
@foivosstamopoulos9709
@foivosstamopoulos9709 Жыл бұрын
Thank you so much Philipp! You are a great tutor!
@khiariyoussef3226
@khiariyoussef3226 2 жыл бұрын
I usually don't set messages in the view model, i only send codes or states which can be mapped to the correspond resources in the UI layer.
@PhilippLackner
@PhilippLackner 2 жыл бұрын
And what do you do if the error comes from the repo? (sometimes from the API, sometimes a string resource)
@khiariyoussef3226
@khiariyoussef3226 2 жыл бұрын
@@PhilippLackner mapping them to custom codes? Usually I let the errors propagate to the ViewModel where I catch them and send a code to the UI instead.
@kwabenaberko5317
@kwabenaberko5317 2 жыл бұрын
Exactly. This is what I do as well. In the case of errors, data source errors are converted to domain errors(sealed classes) which the UI receives and maps to the necessary string resources
@javimardeveloper
@javimardeveloper Жыл бұрын
That is really cool. My question is how to use inside a use case, since those should be Android agnostic.
@xenofonkarydis6406
@xenofonkarydis6406 2 жыл бұрын
That's a very nice solution, although it requires to have your project built upon Jetpack Compose!
@PhilippLackner
@PhilippLackner 2 жыл бұрын
No it doesn't, just leave away the composable function and use the other one taking the context instead
@talkativebreakdown2311
@talkativebreakdown2311 2 жыл бұрын
@@PhilippLackner Hello Philipp, but I can't create LocalContext.current in activity file. Isnt it only for Compose?
@PhilippLackner
@PhilippLackner 2 жыл бұрын
@@talkativebreakdown2311 yes, inside an activity just pass this
@hossamqandel5638
@hossamqandel5638 2 жыл бұрын
but is this approach with passing context inside every ui will make nay problem?
@mesutemrecelenk5447
@mesutemrecelenk5447 2 жыл бұрын
Hi Philipp. Thanks for your best practice sharing. Can we collect this message in MainActivity and trigger showing snackbar in our setContent {...} for all composable screens?
@bleachedlizard
@bleachedlizard 2 жыл бұрын
One problem I've found with using this pattern is that if you ever want to access these strings by calling the asString function from within the viewmodel (for example, to perform some validation on them) you can't, as you can't have access to the Context from within the viewmodel. Basically, as soon as you wrap the String/resource in a UiText object it becomes inaccessible from anywhere where you don't have access to the Context. Is there any solution to this?
@PhilippLackner
@PhilippLackner 2 жыл бұрын
No, because the value of the string isn't fully clear until it reaches the UI layer. Could be any language and you also want to make sure that the ui refreshes when the language is changed. That doesn't work if you read it before reaching the ui since it won't be re-read on a Config change
@withKaaveh
@withKaaveh 2 жыл бұрын
Hey Philipp, Do you make a video and explain how you record and create these tutorials videos after you bought MacBook?
@snow4dv
@snow4dv 9 ай бұрын
Isn't it better to write an extension composable function and put it in presentation layer? In that case it would be possible to make viewmodel separated from compose (if we don't use compose-specific stuff like mutable states). It also looks more like a shortcut so extension function fits better for it to me
@Renaro
@Renaro 2 жыл бұрын
Very good content! Using an interface wrapper for the resources injected in the ViewModel would also work right? Then you can easily provide it and also mock it for unit tests.
@critikalfade
@critikalfade 2 жыл бұрын
This is simple and helpful. Thanks!
@sameeryadav8857
@sameeryadav8857 2 жыл бұрын
can someone tell me what context is? I have been seeing it from day 1 when i started with app dev but never knew what it means. If there some article or blog explaining it (in easy ways) please link in reply.
@abdelazizyasser3512
@abdelazizyasser3512 2 жыл бұрын
Hello phillip , thank u so much for your efforts, can i know what's the Channel (include send&receive functions) class in this case ?
@daryldyck7938
@daryldyck7938 2 жыл бұрын
Very helpful - Thanks! I'm thinking we may be able to do something similar to access dark/light theme color values outside of a composable context...
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Yeah that should be possible :)
@ahmedna7543
@ahmedna7543 2 жыл бұрын
Just sent the resource Id to the channel (observable) -> Channel , send a Channel in case you need api strings too , This needs change in 2 line of code , instead of all this.
@masmmaw
@masmmaw 2 жыл бұрын
can we not fill in the argument variable (vararg) because not all cases are like in the video right? sometimes we just display static messages in the snackbar.
@PhilippLackner
@PhilippLackner 2 жыл бұрын
yeah sure, then you just leave it empty
@samilindo1
@samilindo1 2 жыл бұрын
I follow with an implementation very close to yours, but I make an extension of the View class, which allows me to receivereceive the UiText as a parameter, and I set the value internally using the context of the vie itself
@jatinsachdev
@jatinsachdev 2 жыл бұрын
I think that is part of UI - should not be moved to ViewModels. Validation logic in ViewModel should return some status that can be handled on UI to show the proper message from resources.
@PhilippLackner
@PhilippLackner 2 жыл бұрын
That works, however IMO the UI should be as "dumb" as possible. The whole purpose of the VM is to take inputs from the UI and update the state for it. Letting the UI decide how to handle specific statuses puts too much logic into the UI layer.
@jatinsachdev
@jatinsachdev 2 жыл бұрын
In architecture, nothing is right or wrong. What works works. All boils down to maintenance of the project. Since messages are part of UI, changing it on UI layer separates it from other part of the app. State being part of UI does not make it dumb. There will be some composables that are dumb for sure but some require state.
@PhilippLackner
@PhilippLackner 2 жыл бұрын
@@jatinsachdev sure, if you like it more nobody keeps you back. I just prefer a different solution 😄
@jatinsachdev
@jatinsachdev 2 жыл бұрын
@@PhilippLackner 😂
@mustafaammar551
@mustafaammar551 2 жыл бұрын
Thank you BRO 👍👍👍
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Welcome 👍
@UpLiftingU007
@UpLiftingU007 2 жыл бұрын
Thanks for sharing philip
@PhilippLackner
@PhilippLackner 2 жыл бұрын
You are very welcome
@rogercolque
@rogercolque Жыл бұрын
Hi good content Please anyone have and example or Tutorial using XML instead of Compose using Koin and idk if will work if have devices for diferents countries. I already have all strings in different languages..
@vahekhachaturian2424
@vahekhachaturian2424 Жыл бұрын
Very nice trick! However, I don't really see how this can be used if you were to write unit tests on viewmodel
@berkc5323
@berkc5323 2 жыл бұрын
Which android studio theme is this?
@dmitrymukhin9050
@dmitrymukhin9050 2 жыл бұрын
I would advise you to use polymorphism instead of when(this)
@skullkrum20
@skullkrum20 2 жыл бұрын
I wonder who suggested this in one of your live streams on Twitch 💪😁
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Ahh it was you, I remembered someone did, but forgot who it was :DD
@skullkrum20
@skullkrum20 2 жыл бұрын
@@PhilippLackner I have learnt a lot from you, at least once I (well not really teach you coz you would get here eventually anyway) I could help you! 😁 Gotta love the Android community!
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Thanks, you indeed did help me with that. Especially in a live stream, rather simple things are often so out of sight :D Gotta keep using your library for future videos!
@s-w
@s-w 2 жыл бұрын
I like it. I've just been passing either strings or string resources, but it makes sense to do this for consistency.
@skullkrum20
@skullkrum20 2 жыл бұрын
@@s-w it’s not just for consistency. Imagine you have a TextView that may have to display either text coming from the server or a string resource. Ideally you want to have a single outlet in the ViewModel for that TextView and for that you need something like this
@rpitpatel1004
@rpitpatel1004 Жыл бұрын
If we have 10 string resources to use in Ui then need 10 state in VM and it will quickly become messier. If I understand that correctly right?
@PhilippLackner
@PhilippLackner Жыл бұрын
Why, you only need this for strings that require some calculation based on logic. Not for static ones
@maxhartung97
@maxhartung97 2 жыл бұрын
Hi Philip, do you have any videos regarding generating views programatically ? Without XML ? If not, do you have any recommendations ?
@PhilippLackner
@PhilippLackner 2 жыл бұрын
You just create them as a normal instance, like any other class. Then you add them to an existing layout using layout.addView(yourView)
@mieszkokozma4239
@mieszkokozma4239 2 жыл бұрын
A problem with this approach is that two identical strings with params will return false when compared. One way to work it around would be to replace class with data class implementation with fixed amount of parameters instead of vararg. data class StringResource( @StringRes val resId: Int, val arg1: Any? = null, val arg2: Any? = null, val arg3: Any? = null, val arg4: Any? = null, val arg5: Any? = null ) : UiText() fun asString(context: Context): String { return when (this) { is DynamicString -> value is StringResource -> context.getString(resId, *arrayOf(arg1, arg2, arg3, arg4, arg5).filterNotNull().toTypedArray()) } }
@denchic45
@denchic45 2 жыл бұрын
Great! It seems to me that it is possible to make the arguments type also UiText, on which the asString fun would be called, so it would be possible to do more complex combined strings
@PhilippLackner
@PhilippLackner 2 жыл бұрын
But why would you do that, you can use string arguments
@denchic45
@denchic45 2 жыл бұрын
@@PhilippLackner But what if you need to concatenate 2 string resources?
@PhilippLackner
@PhilippLackner 2 жыл бұрын
@@denchic45 then you do uiText1.asString() + uiText2.asString()
@denchic45
@denchic45 2 жыл бұрын
@@PhilippLackner I could be wrong, but then a warning might appear: "Do not concatenate text rendered with setText. Use a resource string with placeholders."
@cassiobruzasco
@cassiobruzasco 2 жыл бұрын
@@denchic45 isolate it in a val and then use the val at the setText
@bringoff
@bringoff 2 жыл бұрын
What about creating a wrapper interface, let’s say, LocalizationProvider, with getString function, pass an implementation that works like proxy for context to ViewModels in real code and mock the interface for unit tests? Works for both xml and compose.
@niranz7745
@niranz7745 2 жыл бұрын
I agree. I think this approach is better
@汪枭杰
@汪枭杰 2 жыл бұрын
"pass an implementation that works like proxy for context to ViewModels" Will your implementation hold context internally? If yes, it's actually passing context into ViewModel, which may lead to context leak. Another concern for this is, if device locale changes, string in liveData won't be updated. So it's still a better solution to get it in UI layer
@bringoff
@bringoff 2 жыл бұрын
@@汪枭杰 application context cannot leak because its lifecycle is the same as the whole application. Activity is recreated after configuration change (or callback is triggered if you change this behavior in manifest) or onConfigurationChanged is called, so you are free to handle it the way you like.
@DiegoNovati1
@DiegoNovati1 2 жыл бұрын
I don't like at all the solution: the ViewModel manages error messages, and it should be done instead by the view layer. Instead of passing a String or a UiText (ViewModel deals with the UI !!!!) you should pass a sealed class defining all the possible errors; the View layer will convert the error in the string to display (in this way the ViewModel notify an error to the view, the view will convert to a string using an extension function for that specific sealed class without breaking the MVVM architecture)
@PhilippLackner
@PhilippLackner 2 жыл бұрын
That's another way to do it that just puts more logic in your UI
@DiegoNovati1
@DiegoNovati1 2 жыл бұрын
@@PhilippLackner Not in the View, but in the View layer (using the same @Composable logic, that belongs to View) and you are using a @Composable in your ViewModel.
@PhilippLackner
@PhilippLackner 2 жыл бұрын
@@DiegoNovati1 the viewmodel belongs to the presentation layer. And I'm not using composable in the viewmodel, it's used in ui text.
@DiegoNovati1
@DiegoNovati1 2 жыл бұрын
@@PhilippLackner UiText contains a @Composable function (asString()) so it uses a View libraries breaking the MVVM architecture: the ViewModel should have no knowledge of the UView layer. To bypass the problem you should define an interface for the UiText, and defines it in the ViewModel layer, and then implement it in the View layer using the @Composable.
@PhilippLackner
@PhilippLackner 2 жыл бұрын
@@DiegoNovati1 who says thats a problem? Then you also wouldn't be allowed to use compose state in a viewmodel lol
@alishernuraliev9075
@alishernuraliev9075 2 жыл бұрын
Thank you very much !)
@dev_jeongdaeri
@dev_jeongdaeri 2 жыл бұрын
super cool!
@thegreatwarrior4989
@thegreatwarrior4989 2 жыл бұрын
Can you please make a video about material 3 and jetpack compose insets
@abawell
@abawell 2 жыл бұрын
Thanks for your solution. Personally I use the application context. Is this a problem ?
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Yeah, then you can't write local unit tests for your VM and have to make them instrumented tests which take a lot longer
@umnikya7874
@umnikya7874 11 ай бұрын
So cool!
@arfinhosain
@arfinhosain 2 жыл бұрын
what is ur code editor font?
@j2shoes288
@j2shoes288 Жыл бұрын
ViewModel is part of the Presentation layer, and as such, not sure, why you want to avoid the context inside it?
@PhilippLackner
@PhilippLackner Жыл бұрын
To make it testable with JVM tests
@smreha
@smreha 2 жыл бұрын
Great video 👍
@martindinaputra8601
@martindinaputra8601 2 жыл бұрын
hi philipp, about what you said in the video that if we use application context in the viewModel, we wouldn't be able to run the test in the JVM environment. So I actually used this approach via dependency injection like the code below @HiltViewModel class SomeViewModel @Inject constructor( private val repository: SomeRepository, @ApplicationContext private val injectedContext: Context ) : BaseViewModel(repository) { fun someFunction(): String { // do something return injectedContext.getString(R.string.some_string) } } and as for the unit test, I simply mock the Context object and pass it to the viewModel that I'm testing(i'm using mockk for the mocking library) @Test fun `test someFunction`() { val injectedContext = mockk() every { injectedContext.getString(R.string.someString) } returns "some string" val viewModel = SomeViewModel( SomeRepository(), injectedContext ) val result = viewModel.someFunction() assertEquals("some string", result) } it works just fine, but perhaps I'm missing some of the points that you're trying to say in your video about this & that this approach might be a bad practice after all. Please tell me what do you think about this, Thanks!
@amineayachi335
@amineayachi335 2 жыл бұрын
OMG i was looking for this video long time ago i was using strings ids as int then call resources on that int in jetpack compose still didnt watch the video !!
@amineayachi335
@amineayachi335 2 жыл бұрын
Similaire to my solution but with more options thank master great solution
@miladhashemzadeh5626
@miladhashemzadeh5626 2 жыл бұрын
Good Solution
@John-qt6qk
@John-qt6qk 2 жыл бұрын
Thanks
@a.bastiao4312
@a.bastiao4312 2 жыл бұрын
I watched half of this video thanks to KZbin suggestion. But what I don't get is why a ViewModel cannot be unit tested if the app context is injected. Since context is an interface it can easily be mocked. Isn't that one of the benefits from dependency injection? Allow provide test doubles or use mocking libraries, right?
@PhilippLackner
@PhilippLackner 2 жыл бұрын
You should avoid mocks as much as possible, they can quickly make your test suite break when things change. I only use them for code from 3rd party libraries I don't own or if it's a legacy code base and I have to write some tests to refactor it
@a.bastiao4312
@a.bastiao4312 2 жыл бұрын
@@PhilippLackner you just read the mock part. Why not an interface that can be injected into the viewModel? A simple interface with an implementation that takes context as constructor argument and has a function to provide the strings the way you need. But to answer the mocks and the third parties, isn't that applicable to context?
@PhilippLackner
@PhilippLackner 2 жыл бұрын
@@a.bastiao4312 an interface to provide resources works, that's true. However you still need to think about how to pass both string resources and dynamic strings from the repo to the viewmodel
@a.bastiao4312
@a.bastiao4312 2 жыл бұрын
@@PhilippLackner that's why I watched only half of the video. I was never going to have issues to solve that problem. The data layer would provide an error message wrapped on result error and that was passed to tbe ui. The edit text validation isn't related. So to me isn't an issue. The issue are the KZbin recommendations
@Zihad
@Zihad 2 жыл бұрын
That is very smart.
@MaisUmSomente
@MaisUmSomente 2 жыл бұрын
Instead of creating a new function just to pass the context, I couldn't just put the context inside the Composable like this @Composable fun asString(): String { val context = LocalContext.current return when(this) { is DynamicString -> value is StringResource -> context.getString(resId, *args) } }
@Dynamitemedina
@Dynamitemedina 2 жыл бұрын
Almost didn't see the point until I saw the get string composable.
@bboydarknesz
@bboydarknesz 2 жыл бұрын
Jesus chirst, finally this is what I am looking for!!!! But.... Is it really okay to pass the context? It's always memory leaks issue they say..
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Passing context to a function is not an issue. It just gets problematic if you store it in a static field (companion object) of an object that has a different life time than the activity the context comes from. Either way, if you use the app context, leaks can't happen.
@bboydarknesz
@bboydarknesz 2 жыл бұрын
@@PhilippLackner well that makes sense. Thank you for answering my doubt years!
@jatinvashisht4293
@jatinvashisht4293 2 жыл бұрын
Using channels and converting them to flows is a good practice?
@RackaApps
@RackaApps 2 жыл бұрын
Yes. They'll still behave like a Channel. That's why the asFlow() extension function exists which takes care of that
@jatinvashisht4293
@jatinvashisht4293 2 жыл бұрын
@@RackaApps alright, thanks for clarifying
@udhdbdjxisskka
@udhdbdjxisskka 2 жыл бұрын
Or if you don't use Compose, you can return from viewModel just the int resource id and do context.getString in the fragment or view.
@PhilippLackner
@PhilippLackner 2 жыл бұрын
This is not compose specific, returning the resource ID won't allow you to pass dynamic errors coming from the api
@deeplathia4304
@deeplathia4304 2 жыл бұрын
How can we achieve the same using xml?
@bheemnegi3229
@bheemnegi3229 2 жыл бұрын
Use extension function to get String, fun error.asString(context: Context) { if(Dynamic){ return DynamicString } else { return context.getString(resId) } } And then set it to text
@ipvoodoo
@ipvoodoo 2 жыл бұрын
Avesome! 👍
@cloakrabbit767
@cloakrabbit767 2 жыл бұрын
You can unit test viewmodel with context and no emulators with Robolectric. But ofc. without Robolectric its faster
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Yep that's something you should avoid if possible
@cloakrabbit767
@cloakrabbit767 2 жыл бұрын
@@PhilippLackner Sure. What I have been doing is creating class ResourceProvider that has fun getString(resId, vararg format) and itself has Context. Other places that inject it its then simpler to mock as it is a constructor parameter. Any downside to this? Thanks for the reply :-)
@PhilippLackner
@PhilippLackner 2 жыл бұрын
@@cloakrabbit767 no, good approach as well :)
@MrRahulmalik
@MrRahulmalik 2 жыл бұрын
What if we are not using compose? Then how do we do that?
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Nothing changes
@umuttekin4967
@umuttekin4967 2 жыл бұрын
No it changes. You need to pass context if you don't have composable. That's mean you cannot access asString function in viewModel. So if you don't have compose in your project, this will not work as expected.
@PhilippLackner
@PhilippLackner 2 жыл бұрын
@@umuttekin4967 no, the only thing you need to do for xml is to remove the composable function and just use the other overload that takes the context instead. There's no need to call asString in the VM
@umuttekin4967
@umuttekin4967 2 жыл бұрын
@@PhilippLackner But the purpose of this video is the using string resources in a VM. If i don't need to call asString in the VM what's the point? I want to access string resources in the VM but if i don't have compose in my project according to this video i can't access it.
@frozen1093
@frozen1093 2 жыл бұрын
@@PhilippLackner could you pls explain it more detailed? I'm new to android dev and can't figure out how to do that. pls
@GeolseuDeiGamers
@GeolseuDeiGamers 2 жыл бұрын
Is this possible in XML?
@PhilippLackner
@PhilippLackner 2 жыл бұрын
yeah, nothing changes
@GeolseuDeiGamers
@GeolseuDeiGamers 2 жыл бұрын
@@PhilippLackner thank you for the gold content
@aliakram1145
@aliakram1145 2 жыл бұрын
Seems like you have flue, if yes get well soon bro.👍
@PhilippLackner
@PhilippLackner 2 жыл бұрын
Yeah, I already feel better, thanks! :)
@elelan
@elelan 2 жыл бұрын
👌👌👌
@mieszkokozma4239
@mieszkokozma4239 2 жыл бұрын
I went a slightly different way. I'm injecting an instance of getStringUseCase, which internally uses ApplicationContext to resolve strings and is exposing a method "operator fun invoke(stringId: Int, vararg formatArgs: Any): String". It didn't fail me so far, and this way I can have a state with simple String values.
@skullkrum20
@skullkrum20 2 жыл бұрын
If you save your resolved strings in the ViewModel, it is wrong. Because if the user changes languages and goes back to your app, your views will not be automatically updated and the previous language will still be used. This is because the ViewModel will get reused and the Strings are already resolved. If you resolve them in the UI, since the fragment/activity is recreated, it will call the "getString" again and so update the language of the text.
@mieszkokozma4239
@mieszkokozma4239 2 жыл бұрын
@@skullkrum20 That's correct, however in the application that I work with this doesn't really matter. I prefer the convenience of use over the "bulletproof" solution, which is maybe going to slightly improve the UX for 0.01% of the users once (how often are you changing the language on your phone, apart from the development testing purposes?). That's how I see it. Many strings come already translated from the server which only knows about the local language at the time of data being asked, so we would end up having mixed translations anyways.
@skullkrum20
@skullkrum20 2 жыл бұрын
@@mieszkokozma4239 For you it may not be a common use case, but there are a lot of families and contries that speak multiple languages and they may want to sometimes change them, I imagine having to restart the app is annoying in such cases. Also, Android is going to support language per apps, so this use case will become even more common. I do understand the point of mixed languages though, it feels like a bad solution that the server gives you text rather than text ids that then get translated into resource ids that can also be translated. Anyway, like you said, it won't be a big deal most of the times :)
@lglf77
@lglf77 2 жыл бұрын
Muito complicado seu vídeo, já inicia com milhões de código na tela, não é aprovável para iniciantes
@MrY21610
@MrY21610 2 жыл бұрын
👍 👍 👍 👍
@GG9K71
@GG9K71 Жыл бұрын
Make a static app context instance inside your Application, and use it.. 😂
@PhilippLackner
@PhilippLackner Жыл бұрын
Then any classes that use it won't be locally unit testable anymore, since they use Android dependencies
@GG9K71
@GG9K71 Жыл бұрын
@@PhilippLackner Yes I know, I was joking
@КонстантинСоловьев-в7п
@КонстантинСоловьев-в7п 2 жыл бұрын
Son unos XX18LIKE.Uno de los mejoress conciertos Mañas no 10 se l 💯💞😍
How to Automate Tasks Using Gradle - Android Studio Tutorial
18:55
Philipp Lackner
Рет қаралды 27 М.
快乐总是短暂的!😂 #搞笑夫妻 #爱美食爱生活 #搞笑达人
00:14
朱大帅and依美姐
Рет қаралды 10 МЛН
How To Choose Mac N Cheese Date Night.. 🧀
00:58
Jojo Sim
Рет қаралды 84 МЛН
The Singing Challenge #joker #Harriet Quinn
00:35
佐助与鸣人
Рет қаралды 40 МЛН
ViewModels & Configuration Changes - Android Basics 2023
18:46
Philipp Lackner
Рет қаралды 131 М.
How to Validate Forms with Clean Architecture (You're Doing it Wrong)
41:08
5 Fatal Coroutine Mistakes Nobody Tells You About
18:15
Philipp Lackner
Рет қаралды 89 М.
Should You Use Compose State or StateFlow in Your ViewModels?
13:59
Philipp Lackner
Рет қаралды 81 М.
Cleaner Code With Use Cases - The Full Guide
14:16
Philipp Lackner
Рет қаралды 52 М.
6 Design Patterns Every Android Developer Must Know
14:16
Philipp Lackner
Рет қаралды 82 М.
TypeScript - The Basics
12:01
Fireship
Рет қаралды 1,5 МЛН
Full Guide to Jetpack Compose Effect Handlers
24:56
Philipp Lackner
Рет қаралды 97 М.
Compose Navigation Just Got SO MUCH EASIER 😱
12:00
Philipp Lackner
Рет қаралды 65 М.
What's New in .NET 9 with Examples
25:02
Nick Chapsas
Рет қаралды 33 М.
快乐总是短暂的!😂 #搞笑夫妻 #爱美食爱生活 #搞笑达人
00:14
朱大帅and依美姐
Рет қаралды 10 МЛН