Тёмный

The Top 3 State Management Mistakes On Android 

Philipp Lackner
Подписаться 172 тыс.
Просмотров 22 тыс.
50% 1

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

Наука

Опубликовано:

 

13 янв 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 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 4 месяца назад
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...
@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.
@mircodev
@mircodev 5 месяцев назад
Thx for the video. Tip 2 was very helpful for me.
@DiabloZq
@DiabloZq 5 месяцев назад
Thanks you! Interesting way, before i did it with mutex, but now i see that more direct way.
@abdallahsafieddine1632
@abdallahsafieddine1632 5 месяцев назад
Pretty much basics and official recommendations.. good job
@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.
@yuriifeshchak7124
@yuriifeshchak7124 Месяц назад
Thanks a lot Philipp for helpful tips. Your videos improve my Android Dev skills and my English as well.
@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
@user-xz2lc8ni5l
@user-xz2lc8ni5l 5 месяцев назад
Very important concepts thank you, people very often encounter in this scenarios in real world projects.
@fakhrymubarak665
@fakhrymubarak665 5 месяцев назад
thanks for the knowledge bro!
@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
@unknownBoy85lover
@unknownBoy85lover 5 месяцев назад
Thank you sir ❤
@jvp8447
@jvp8447 5 месяцев назад
You are awesome!
@rsumanradhakrishnan3747
@rsumanradhakrishnan3747 5 месяцев назад
Hey philip, please make video related to KMP
@HritikGupta722
@HritikGupta722 5 месяцев назад
Thank You !
@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?
@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!
@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
@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.
@user-ku4hz2wz2i
@user-ku4hz2wz2i 5 месяцев назад
Thank you
@amineharbaoui7408
@amineharbaoui7408 4 месяца назад
is any one know what Philipp did you move the bloc inside the viewModelScope using the keyboard ?
@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 :)
@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.
@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)
@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.
@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
@probot7588
@probot7588 5 месяцев назад
Can you please make a video on mvvm with firebase and pagination 3
@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) } }
@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!
@salmakd3586
@salmakd3586 5 месяцев назад
Quick question: can we pass arguments from one destination to another using parcealble data classes also?
@osisuper98
@osisuper98 5 месяцев назад
Not without doing it the hacky way. Why not just save whatever you are trying to pass into a db?
@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.
@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
@foryoutube5118
@foryoutube5118 5 месяцев назад
Green -> Red Thumbnail
@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
@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
Далее
5 Fatal Coroutine Mistakes Nobody Tells You About
18:15
I Built 100 Homes And Gave Them Away!
09:36
Просмотров 45 млн
Bottom Nav Bar #03 | Material 3 | Jetpack Compose
12:21
Compose Modifiers deep dive
21:02
Просмотров 32 тыс.
Flutter Provider EASY Tutorial
9:43
Просмотров 42 тыс.
Что не так с Sharp? #sharp
0:55
Просмотров 117 тыс.