The Top 3 State Management Mistakes On Android

  Рет қаралды 21,806

Philipp Lackner

Philipp Lackner

5 ай бұрын

In this video I will show you the Top 3 State Management Mistakes On Android.
💻 Let me be your mentor and become an industry-ready Android developer in 10 weeks:
pl-coding.com/drop-table-ment...
⭐ Courses with real-life practices
⭐ Save countless hours of time
⭐ 100% money back guarantee for 30 days
⭐ Become a professional Android developer now:
pl-coding.com/premium-courses...
Get my FREE PDF about 20 things you should never do in Jetpack Compose:
pl-coding.com/jetpack-compose...
Regular programming advice on my Instagram page: / _philipplackner_
Join my Discord server:
/ discord

Пікірлер: 84
@96Cpr
@96Cpr 5 ай бұрын
In the part you talk about the _state.update (between 5:00 and 6:00) it's better to also use it.counter instead of state.value.counter.
@PhilippLackner
@PhilippLackner 5 ай бұрын
True, thanks!
@robchr
@robchr 5 ай бұрын
Your saved SavedStateHandle implementation has the same race condition bug as the previous example.
@Crimdog
@Crimdog 5 ай бұрын
yea came to ask that, seems like that suffers from the same mistake as example 1? Or is there something I'm missing?
@hups6648
@hups6648 3 ай бұрын
Yep what do you think about that Philipp?
@iori57
@iori57 Ай бұрын
For solving this I did the following but I am not sure if it works in all conditions, but should fix the race condition, let me know your comments: I created these extension methods for SavedStateHandle: fun SavedStateHandle.getUiStateFlow(initialValue: T): StateFlow = this.getStateFlow("uiState", initialValue) fun SavedStateHandle.updateUiState(uiState: StateFlow, function: (T) -> T) { synchronized(uiState) { val prevValue = uiState.value val nextValue = function(prevValue) this["uiState"] = nextValue } } now in my viewModel, I can do this to get the uiState: val uiState = savedStateHandle.getUiStateFlow( MyUiState( title = "test") ) and if I want to update the state: savedStateHandle.updateUiState(uiState) { it.copy(title = "updated") }
@eugenepopovich2264
@eugenepopovich2264 5 ай бұрын
Thanks for the video. One note. There will not be any race condition in the first case demo. That's because both coroutines run in the main thread and there are no any suspending calls between read and write of the state. However, in case of the alternative dispatcher, such as IO or some suspending call between read and write there will be the race condition.
@pelealexandru
@pelealexandru 5 ай бұрын
thanks, i was just thinking that as well.
@raheemadamboev
@raheemadamboev 5 ай бұрын
agreed
@UsmonWasTaken
@UsmonWasTaken 5 ай бұрын
SavedStateHandle API is good enough to work with, but it would be great if it's type-safe. On top of it, you have to use a synchronized block or Mutex to make it thread-safe
@ngolian
@ngolian 5 ай бұрын
I noticed the sync issue too. In fixing mistake 2 he reintroduced mistake 1!
@pablovaldes6022
@pablovaldes6022 5 ай бұрын
To me the Android saveStateHandle API and the whole ceremony created around process death is unavailable and just not necessary. Use sharedPreferences or a database and everything should be ok.
@deepakbisht4957
@deepakbisht4957 5 ай бұрын
​@@pablovaldes6022well you don't need persistent storage for everything. SaveStateHandle and persistent storage has different usecases. You simply can't blindly store everything...
@abdallahsafieddine1632
@abdallahsafieddine1632 5 ай бұрын
Pretty much basics and official recommendations.. good job
@mircodev
@mircodev 5 ай бұрын
Thx for the video. Tip 2 was very helpful for me.
@khanzadakashif8248
@khanzadakashif8248 5 ай бұрын
For those trying to recreate first one, create a textfield, update it's value via viewmodel, use copy method and then try typing quickly.... I learned it the hard way... 😅
@khanzadakashif8248
@khanzadakashif8248 5 ай бұрын
Third one actually helped me understand a problem we've been facing for quite a long time.
@fakhrymubarak665
@fakhrymubarak665 5 ай бұрын
thanks for the knowledge bro!
@DenzilFerreira
@DenzilFerreira 5 ай бұрын
One thing to consider is that if you save a token in persistent storage, you need to make sure it’s in a secure fashion (encrypted for example). Depending on the token, they may have a shorter or longer lifetime. It becomes an easy attack vector. If the default is null, we could simply ask the user to re-login?
@erayagdogan3389
@erayagdogan3389 5 ай бұрын
There's EncryptedSharedPreference and there's also SQLCipher for database encryption and it can work with Room.
@fardalakter4395
@fardalakter4395 5 ай бұрын
Do you want to relogin everytime you kill the apps ? That would be annoying
@deepakbisht4957
@deepakbisht4957 5 ай бұрын
​@@fardalakter4395no! Create two tokens. One is an access token for a short life span and another one is a refresh token that has a long time span. When your access token expires then don't logout, just hit another api that has a refresh token in the header and it will return a new access token and refresh the token and hit that API again with the new access token... Point to note that Access token is used for authentication and authorisation of all the APIs Refresh token is used only to get new access token and new refresh token...
@DenzilFerreira
@DenzilFerreira 5 ай бұрын
@@fardalakter4395 could be a fingerprint, pin to re-authenticate? That’s what normally secure apps do.
@olivermetz4809
@olivermetz4809 5 ай бұрын
Often you can refresh an expired access token without having to login again using *drumroll*... a refresh token. I'd generally be very careful what to persist.
@LucasAlfare
@LucasAlfare 5 ай бұрын
And what about the multithreading problem on the second topic using the approache of the third topic?
@noebenjaminreynosoaguirre1565
@noebenjaminreynosoaguirre1565 5 ай бұрын
thank you philipp, i didnt know about the options shown by the right click on the logcat window xd
@DiabloZq
@DiabloZq 5 ай бұрын
Thanks you! Interesting way, before i did it with mutex, but now i see that more direct way.
@user-xz2lc8ni5l
@user-xz2lc8ni5l 5 ай бұрын
Very important concepts thank you, people very often encounter in this scenarios in real world projects.
@yuriifeshchak7124
@yuriifeshchak7124 Ай бұрын
Thanks a lot Philipp for helpful tips. Your videos improve my Android Dev skills and my English as well.
@unknownBoy85lover
@unknownBoy85lover 5 ай бұрын
Thank you sir ❤
@jvp8447
@jvp8447 5 ай бұрын
You are awesome!
@Adam-ey7wy
@Adam-ey7wy 5 ай бұрын
Bro, u r the GOAT of Android :) great tips as always! Here is my video request: How to handle google ads/ custom ads in our apps properly
@HritikGupta722
@HritikGupta722 5 ай бұрын
Thank You !
@rsumanradhakrishnan3747
@rsumanradhakrishnan3747 5 ай бұрын
Hey philip, please make video related to KMP
@mustafaammar551
@mustafaammar551 5 ай бұрын
Thank You BRO
@GN9K71
@GN9K71 5 ай бұрын
Let me ask: running two separate coroutines from the viewmodel scope will run the frim the context of the main thread by default, right? In this case how a race conditon will occur?
@user-ku4hz2wz2i
@user-ku4hz2wz2i 5 ай бұрын
Thank you
@ccmonkey1106
@ccmonkey1106 5 ай бұрын
This is a very interesting video. I'll try to apply these solutions in my code base. I have a personal request, Philipp. Can you make an updated video related to preferences datastore? Shared preferences is sorta deprecated right and it would be nice to have a new guide on how to apply preferences datastore nowadays
@PhilippLackner
@PhilippLackner 5 ай бұрын
Shared preferences isn't deprecated :)
@ubersticks
@ubersticks 5 ай бұрын
@@PhilippLackner this guy says it is deprecated: *"Preferences DataStore in 10min (SharedPreferences deprecated)"* by Philipp Lackner, Nov 27 ,2020 🙂
@fardalakter4395
@fardalakter4395 5 ай бұрын
​@@ubersticks😂
@ccmonkey1106
@ccmonkey1106 5 ай бұрын
@@PhilippLackner Thanks for the answer. I'll do my research to avoid questions like that. But if that said, I'm wondering if there's any advantage of learning preferences datastore over shared preferences...
@deepakbisht4957
@deepakbisht4957 5 ай бұрын
​@@ccmonkey1106for simple lightweight solution shared preference is enough but for complex data and better performance especially for larger dataset data store is better as it works asynchronously so it is good for IO operations
@pelealexandru
@pelealexandru 5 ай бұрын
hey Philip, in the first example both coroutines are running on Main thread and since none of them perform a suspend operation, they will always run one after the other and there will never be a race condition in this particular example. am i wrong somewhere? i am pretty new to coroutines so please let me know if i am wrong. thanks!
@amineharbaoui7408
@amineharbaoui7408 4 ай бұрын
is any one know what Philipp did you move the bloc inside the viewModelScope using the keyboard ?
@pablovaldes6022
@pablovaldes6022 5 ай бұрын
I keep saying that savedStateHandle and whatever process API Google created to recover from process death is unscalable and not necessary. You forgot to mention there is a limit in the amount of data you can save and the fact that it needs to be serializable makes it hard to deal with big state classes. Better off using regular preferences or a database. Also you should have mentioned that in modern devices that is very unlikely to happen. That API is one of Google's worst API designs ever created.
@probot7588
@probot7588 5 ай бұрын
Can you please make a video on mvvm with firebase and pagination 3
@ngapps
@ngapps 4 ай бұрын
Hi, what about such kind of update, is it better to change as example _contactUiState.value = ContactUiState.Loading to _contactUiState.update { ContactUiState.Loading }? Similar situation as with copy, but probably happens once? Thanks
@user-wk1vz9wv6j
@user-wk1vz9wv6j 5 ай бұрын
Hi Phillip, I have a question Should we have to use mutableStateOf or mutableStateFlow for state managing?
@vengateshm2122
@vengateshm2122 5 ай бұрын
mutableStateOf can be used inside composable. mutableStateFlow can be used in view model. But technically you can use both inside view mode.
@inuyasha11p
@inuyasha11p 5 ай бұрын
Hi Philipp. I wanted to start learning kotlin and I saw that ur playlist was from 4 years ago. Is it still possible to learn from there or is it too outdated?
@PhilippLackner
@PhilippLackner 5 ай бұрын
The basics never change much :)
@matteoZattera
@matteoZattera 5 ай бұрын
Hi Philipp, can you make a video on how to make an app with an OnBoarding screen using Datastore to save onBoardingCompleted?
@vengateshm2122
@vengateshm2122 5 ай бұрын
// class AppDataStore(context: Context) { private val dataStore: DataStore by context.dataStore(name = "app_settings") private val ONBOARDING_COMPLETED_KEY = preferencesKey("onboarding_completed") val onboardingCompleted: Flow = dataStore.data .catch { exception -> if (exception is IOException) { emit(emptyPreferences()) } else { throw exception } } .map { preferences -> preferences[ONBOARDING_COMPLETED_KEY] ?: false } suspend fun setOnboardingCompleted(completed: Boolean) { dataStore.edit { preferences -> preferences[ONBOARDING_COMPLETED_KEY] = completed } } } // class MyApp : Application() { lateinit var appDataStore: AppDataStore private set override fun onCreate() { super.onCreate() appDataStore = AppDataStore(this) } } // @Composable fun OnboardingScreen(appDataStore: AppDataStore) { val onboardingCompleted by appDataStore.onboardingCompleted.collectAsState() if (onboardingCompleted) { // Show your main app screen // ... } else { // Show onboarding screen Button(onClick = { lifecycleScope.launch { appDataStore.setOnboardingCompleted(true) } }) { Text("Finish Onboarding") } } } // class MainActivity : AppCompatActivity() { private val appDataStore by lazy { MyApp.instance.appDataStore } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MyAppTheme { AppMainScreen(appDataStore = appDataStore) } } } } @Composable fun AppMainScreen(appDataStore: AppDataStore) { val onboardingCompleted by appDataStore.onboardingCompleted .collectAsStateWithLifecycle(lifecycle = LocalLifecycleOwner.current.lifecycle) if (onboardingCompleted) { // Show your main app screen // ... } else { // Show onboarding screen OnboardingScreen(appDataStore = appDataStore) } }
@EmmanuelAgyapong-jn6ue
@EmmanuelAgyapong-jn6ue 3 ай бұрын
Good question, where can I find resources where I can learn Android in more depth? I kind am proficient (making apps), but I realized that I lack the fundamentals.
@salmakd3586
@salmakd3586 5 ай бұрын
Quick question: can we pass arguments from one destination to another using parcealble data classes also?
@abiodunmoses2638
@abiodunmoses2638 5 ай бұрын
Not without doing it the hacky way. Why not just save whatever you are trying to pass into a db?
@sepideh1085
@sepideh1085 4 ай бұрын
i always wonder about defining all the states in a data class and copy the data class when we want to update it . doesn't it causes memory leak issues ? isn't it better to define each state as a separate stateflow and set each of their value whenever we want the state to be updated!? instead of copy the whole data class just to change one of its property each time!
@BelokonRoman
@BelokonRoman 5 ай бұрын
Third case can lead to an issue even without process death because the sessionTOken variable is not thread safe(memory visibility issue)
@ozzy4654
@ozzy4654 5 ай бұрын
Looking at your mentorship program for Feb. There still spots open?
@PhilippLackner
@PhilippLackner 5 ай бұрын
Yes, but not many. Feel free to apply
@hashemmousavi2451
@hashemmousavi2451 5 ай бұрын
Both Coroutines were run on the Main thread. How is it possible to be in a race condition?
@christianricardo4058
@christianricardo4058 5 ай бұрын
It's explained. He said both coroutines may be in the same thread. Boths coroutines first read the initial value before it is updated
@fardalakter4395
@fardalakter4395 5 ай бұрын
​@@christianricardo4058then it's synchronized because it's executed line by line
@lemondog252
@lemondog252 5 ай бұрын
Phillipp could you make another video explain this more?
@hashemmousavi2451
@hashemmousavi2451 5 ай бұрын
@@christianricardo4058 I know l, but it's impossible to have race condition on the same thread.
@vengateshm2122
@vengateshm2122 5 ай бұрын
Try changing the dispatchers and update the counter.
@PSK005
@PSK005 5 ай бұрын
7:50 recently i read some articles. Saved state handle can store 1mb size of data. It's true???
@raheemadamboev
@raheemadamboev 5 ай бұрын
I think it was 2 mb (I could be wrong tho). But yes it has limited capacity.
@raheemadamboev
@raheemadamboev 5 ай бұрын
It throws ParcelTooLarge exception when it gets full
@foryoutube5118
@foryoutube5118 5 ай бұрын
Green -> Red Thumbnail
@paininmydroid4526
@paininmydroid4526 4 ай бұрын
A counter app in Android? Flutter is ruining the world. 🤣
@FerreolYvesPoint-mi3oq
@FerreolYvesPoint-mi3oq 5 ай бұрын
in reality, there could be many more errors
Just try to use a cool gadget 😍
00:33
123 GO! SHORTS
Рет қаралды 85 МЛН
DELETE TOXICITY = 5 LEGENDARY STARR DROPS!
02:20
Brawl Stars
Рет қаралды 22 МЛН
Must-have gadget for every toilet! 🤩 #gadget
00:27
GiGaZoom
Рет қаралды 9 МЛН
Compose Modifiers deep dive
21:02
Android Developers
Рет қаралды 32 М.
Reviewing your React Code: Episode #3
14:27
Youssef Benlemlih
Рет қаралды 3,3 М.
ViewModels & Configuration Changes - Android Basics 2023
18:46
Philipp Lackner
Рет қаралды 102 М.
WorkManager - Android Basics 2023
34:22
Philipp Lackner
Рет қаралды 49 М.
This Is My FAVORITE Error Handling Class
28:57
Philipp Lackner
Рет қаралды 25 М.
How charged your battery?
0:14
V.A. show / Магика
Рет қаралды 6 МЛН
cute mini iphone
0:34
승비니 Seungbini
Рет қаралды 2,2 МЛН
Asus  VivoBook Винда за 8 часов!
1:00
Sergey Delaisy
Рет қаралды 861 М.
сюрприз
1:00
Capex0
Рет қаралды 1,6 МЛН