Hey Philipp, on the first anti pattern, I think the extension function doesn't solve the tight coupling issue as an update on the extension function affects all class using this function.
Outstanding, I thought it will be same old boring stuff other channels are talking about in such videos, but of course, you had to make it cover actual bit more advanced topics and provide awesome knowledge and point of view, thanks!
MainActivity inherits from BaseActivity and you say we have no idea what this BaseActivity brings. You change it to an extension function, but i'm afraid we have no idea which extension functions are available, do we?
You have more control over how you structure your extension functions and how you name the files. Putting your utility functions in a base activity sucks because it violates the single responsibility principle and often the separation of concerns as well
What is the best place to put all extensions together, for example for Activity? A separate file like ActivityExtensions? Great video and huge knowledge. Thanks.
Great video as always Philipp, the example on the first anti-pattern made me think about a case on my job, it's kind of a base class with a method with a lot of logic and there's some child classes that inherit from it and overrites maybe one or two of the secondaries methods cause the differences on behavior are minimal, I guess in a case like this where is not just a toast wouldn't be a bad approach, right?
5 Common Android Anti-Patterns Solutions in a Nutshell: I) Don't use global scope - WHY? memory leaks II) Use dispatcher provider interface and its implemented classes - WHY? testing purposes + constructor injection is the best III) Use fragments instead of activities - WHY? more activities == heavier and slower app + complicated code because of intents (my opinion) IV) Specific module for each requirement - WHY? memory efficiency + cleaner code + testing purposes V) Don't use base classes, use extension functions instead - WHY? Design principle: always favor composition over inheritance
Hi @PhilippLackner, I see the point about base classes, but my question is what if we name it something more understandable? For example for view binding, you need to create a binding object and make it null at the onDestroy function. So what if we create BaseViewBindingFragment just for the view binding do you still think of it as an anti-pattern ?
and maybe create some other base classes for other stuff such as showing the error dialog, and the progress showing. But of course, making sure they follow the single responsibility principle.
Hi Philipp, I have an image uploaded in 15 fragments. I created a base fragment to write the result launcher & image compression. Any solutions for this
Is it a usage of 1 viewmodel for 1 fragment is practical? Or each viewmodel should serve only one modules/function? For example, let say I have 3 fragment, LoginFragment, RegisterFragment, UserFragment. Is it ok that I put all the logic in 1 ViewModel (LoginViewModel) ? Or I have to separate them into 3 different viewmodel?
Hello Phillipp, i got little problem i want to override OnAttach in all my fragments, to communicate with my mainActivity but like chatGpt sad "It's not possible to override onAttach using extension functions because extension functions only add new functionality to existing classes and cannot override existing methods". Do u know some solution better then override it in all my fragments?
I'm sorry.. I didn't understand what you tried to teach with the elimination of the BaseActivity.. You said it would be bad when we change the code inside baseActivity because it would reflect everywhere and create strong coupling. But wouldn't the same thing happen with an extension function? I mean if we change the code inside an extension function, it would be changed in all the places where it is called.. right?
You can still better separate your extension functions, create overloads and put them in different files. If you put all that in your base activity, it will grow to death at a certain point. Also a file with extension functions has a clear purpose. You know what's in there. You don't know that with a class called BaseActivity.
The 1st tip doesn't really solve the tight coupling or having methods placed in a separate file where they are "hidden"... It's the same with an extension function class, you have to navigate to it to discover all those "hidden" methods...
You cant say using BaseClasses is an anti pattern , i have used some BaseActivity and BaseFragment and BaseViewmodel which makes life very easy for me , you need to know how to structure your Base classes
I've written that in another comment: If you have a base activity that has a clear purpose (and only one!) and also clarifies that purpose in its name (so it's not called BaseActivity), then this is fine. Most often, that won't be the case though.
@@PhilippLackner Not always though , We can have BaseClasses which remove all boilerplate code , I always use BaseViewModel which expose LiveData/StateFlow and the implementation overrides it as MutableLiveData/MutableStateFlow because i absolutely hate that private _MutableLiveData / public LiveData pattern, BaseFragments/BaseActivity which connect the dagger components . etc etc
Totally agree with A Abishek. There are instances when you're designing for inheritance because you want to have protected visibility. The suggestion to use Kotlin's extension functions makes it public for any class. In the case of the video, it would be a public method for any Activity. This issue becomes even more compounded when you are developing a library/SDK where you have an implementation that is specific to the domain of that library/SDK but then resorting to Kotlin's extension functions would expose it beyond the original domain. If that library would break or refactor that implementation or the method signature, this is going to be a compile-time issue for the client project that has imported the library/SDK.
I think Instead of using Base Activities and Base Fragments, - besides Extension function - we can use Strategy Pattern because requirements change over time and our code must be ready for it. == Open-Closed Principle && Favor Composition over Inheritance
Thank you very much for your explanation! I just wanted to ask about modules. Like..I have services (actually, they are repos when you think about it...) that read fro CSV. Aand...I don't understand why should I use any scope other than Singleton? Let's say, I will use ViewModelScope (if there is one, I don't remember). So as I understand, with every new ViewModel instance new instance of repo objects will be created? If that's true, why would I need that? Won't it reduce performance by more frequent garbage collection? What am I missing? What scopes are needed for? And thank you very much once again for your content!
@@PhilippLackner I see, thanks! After your video I started to use ViewModelScope. But I don't yet fully understand when VM is destroyed. Welp, it's a rabbithole, I guess)) New answers, new questions!
I don't agree about base classes. They help one protect from changes of framework api. E.g. some new android api sets some field nullable/non-nullable, or a package name changed. For me, it's better to have as little direct derivatives from framework classes as possible, because you have no control on them
Sometimes without base classes it's very hard. Suppose we have 20 fragments and every fragment needs to execute something only 1 minute. Fo that I need to create CountDownTimer and after finish just exit that fragment. But it's not the right way to write CountDownTimer logic in every fragment separately, instead I can create that timer in my BaseFragment, start it in onCreateView(). After this I don't need any single line of code in my 20 fragments, I just need to extend BaseFragment. But I'm also agree with you, because in some cases like toasts or similar things are bad practices and no need of base classes in that case.
@@PhilippLackner Why to make it singleton if I don't need it for my whole application lifetime? Maybe in some cases I won't use any of these 20 fragments. And either way I need to put the observe logic in all 20 fragments.
@@haykmkrtchyan7093 yeah or scope it to the activity if all fragments share the same one. If you want to share the same timer instance between multiple fragments, that must be the case
@@PhilippLackner Understood. No they don't share the same instance, I can have like 2-3 visible fragments at the same time and they run their own timers. Just to prevent code duplication I used base fragment. I understand your point too, if there will be bunch of code, it will be hard to maintain))
I have a question regarding the first issue which is "using base classes". What about such a case where we create base class to handle hiding keyboard whenever we push new fragment. Is that ok or do you have better solution for this, cause idk if there is a case in which we do not want the keyboard to hide
Starting activity inside recycleview adapter without passing context because according to my knowledge passing context is a bad practise as it leads to memory leaks then what's the solution to that problems. Correct me if anything wrong
There's no need to pass context to adapter, you can get it from views in ViewHolder. I would personally not start another activity inside adapter and handle it inside the activity/fragment which uses the adapter.
Create an interface with a function name it navigate or whatever, let your activity implement the interface then in adapter constructor define a parameter of type the interface you created. When you click ab utton in your item just call the fuction from your interface and also you can pass the item the postion you clicked
I don't think so base activities or base fragments are anti pattern In my current project I'm using my base fragments to inject dependencies which are required in every fragment and also helped me a lot and for singletons we can write wrapper classes too to mock these And like you have mentioned methods like showToast() For these kinda functions we can make extensions for these like for registering subscriber of event bus etc. Same case for base adapters we can make generic base adapters from where we just have to return view holders It will concise our code for recyclerview adapters
And if at some point in your project you have a fragment that doesn't need that dependency? Or you end up that you need to change the dependency for some fragments? You only have the option to change it for all fragments or other fragments will get access to the dependency even if they don't need it. This coupling is something you want to avoid. New people who will see your normal fragments will have no clue that there is actually an important dependency in your base class. It doesn't have a responsibility and therefore shouldn't exist
@@PhilippLackner and hats off to you bro♥️ seriously I feel very happy after watching your videos that their is someone who loves to work with latest frameworks and libraries I saw these days mostly people are teaching android on old techs and I think this is the platform where they can upgrade their skills according to new era of android
According to you baseActivity is antipattern and the reason is just a toast. Actually I never used baseActivity for a single toast. You can achieve a lot of functionality through base activity. What if you want to do some work in oncreat of every activity. Base activity comes to rescue.
Your base classes use-case example is so poor in programming context. Yes, such functions as show/hide keyboard, toasts, snackbars must be provided as extension kotlin functions. But there are several cases when base classes supports you. in ex. u have very complex custom dialog system, where header/content/footer of such dialogs can be a custom views as well. At this point your extension functions (or any other programming approach beside of base classes) obfuscates the code instead of help.
Great Video! I wish I could have watched this 12 days ago 🙁. I had a bug with #5. I assumed that statics were eliminated after the app was terminated but of course that's not the case... I wrote up a stackoverflow question on it and didn't believe the answer I got until I saw it for my self... 😶
Bro, Sorry if I am going to be harsh but I stopped your video at the first part about BaseClasses because you didn't propose the obvious solution, didn't you hear about overriding functions?, you could've just made your showToast() an open function with a default implementation, and say you want your LoginFragment to have a different implementation, so you override it there and none of the other sub classes of the BaseFragment is affected.
Sorry but you really lost me at the dispatcher part. For starters you don't use any dispatcher other than main in your ViewModel. And to change that in you tests you can use setMain from the coroutine test library. And in layers below that you can just inject the needed dispatchers in the constructor so you can change it whenever you want to. It's time people get past this notion that you need to write worse production code just so as to provide testing hooks since, you know, that's also an anti pattern.
No, not really, I disagree. You don't always use the main dispatcher in your view model. Your viewmodel contains your business logic and could therefore contain long running and CPU heavy tasks which use the default dispatcher. If you then need to test that function and control the coroutine, you have to replace it with a test dispatcher.
@@PhilippLackner You have repositories for business logic. ViewModels should only be used for state management. Not that you can't put business logic in there but the fact that you might need to use separate dispatchers to do so would suggest that it's not a good idea.
Hey Philipp, on the first anti pattern, I think the extension function doesn't solve the tight coupling issue as an update on the extension function affects all class using this function.
Philipp's happiness while recording this video was on 🔥🔥
You're killing it Phillipp, this is an outstanding video!
I so appreciate these type.
Heck, I like all your videos.
Keep up the good work man!!
Thanks so much Matt!
Please continue this series! This is the kind of information that is hard to come by. I wish I knew this when I started.
6. Using Kotlin instead of Java
😂 one can use Java to take a trip of nostalgia
hahahahaaha....
Use coding in flow instead of Philipp and Mitch tutorial 😝😝😝
Please elaborate on that :D
Thanks Philipp, can you make a video on *"How to use sealed classes in android"* with a practical example
I really want this !!!!!
Thanks for the idea :)
@@PhilippLackner Welcome sir
Hey! How did you do bold in the comments???
ahh!, *I see*
Outstanding, I thought it will be same old boring stuff other channels are talking about in such videos, but of course, you had to make it cover actual bit more advanced topics and provide awesome knowledge and point of view, thanks!
Thank you!
Thank you Philip. Today's morning started from your video😄😊 nice explanation 👍
MainActivity inherits from BaseActivity and you say we have no idea what this BaseActivity brings. You change it to an extension function, but i'm afraid we have no idea which extension functions are available, do we?
You have more control over how you structure your extension functions and how you name the files. Putting your utility functions in a base activity sucks because it violates the single responsibility principle and often the separation of concerns as well
What is the best place to put all extensions together, for example for Activity? A separate file like ActivityExtensions? Great video and huge knowledge. Thanks.
Great video as always Philipp, the example on the first anti-pattern made me think about a case on my job, it's kind of a base class with a method with a lot of logic and there's some child classes that inherit from it and overrites maybe one or two of the secondaries methods cause the differences on behavior are minimal, I guess in a case like this where is not just a toast wouldn't be a bad approach, right?
Hey Philipp. Do you use @Binds annotation in Dagger Hilt?
Hi Philipp, I want to learn making app offline-online with livedata kotlin MVVM. Have you created this tutorial before?
5 Common Android Anti-Patterns Solutions in a Nutshell:
I) Don't use global scope - WHY? memory leaks
II) Use dispatcher provider interface and its implemented classes - WHY? testing purposes + constructor injection is the best
III) Use fragments instead of activities - WHY? more activities == heavier and slower app + complicated code because of intents (my opinion)
IV) Specific module for each requirement - WHY? memory efficiency + cleaner code + testing purposes
V) Don't use base classes, use extension functions instead - WHY? Design principle: always favor composition over inheritance
Excellent Video, very useful, Greetings from Caracas, Venezuela
Hi @PhilippLackner, I see the point about base classes, but my question is what if we name it something more understandable? For example for view binding, you need to create a binding object and make it null at the onDestroy function. So what if we create BaseViewBindingFragment just for the view binding do you still think of it as an anti-pattern ?
and maybe create some other base classes for other stuff such as showing the error dialog, and the progress showing. But of course, making sure they follow the single responsibility principle.
Wait a minute, can't you also override the `showToast`, if it is defined in the `BaseActivity`?
Yup, He did not find it yet maybe. 😊😊😊
that's pretty amateur on his part.🙏🙏🙏
I mostly liked the hard coding dispatchers chapter.
Thanks, Philipp
You're welcome!
Hi Philipp, I have an image uploaded in 15 fragments. I created a base fragment to write the result launcher & image compression. Any solutions for this
Philip, please explain lazycolumn with fetching data from an api by using volley library because I need in my project?
Are they cases in android where we would have to use GlobalScope or we should never to that in android ?
Thanks Philipp!!! Really great and informative video!
Is it a usage of 1 viewmodel for 1 fragment is practical? Or each viewmodel should serve only one modules/function?
For example, let say I have 3 fragment, LoginFragment, RegisterFragment, UserFragment.
Is it ok that I put all the logic in 1 ViewModel (LoginViewModel) ? Or I have to separate them into 3 different viewmodel?
Separate view model is always ideal solution. But for simple fragment we can use shared viewmodel
@@praveenvinopv9929 shared viewmodel live as long the container activity ?
@@osamam.g7194 yea, since viewmodel live along activity, so I wonder which approach is best practise for creating viewmodel
I usually separate my viewmodel based on feature , so that i can plug and play thr functionality anywhere in the app
Hello Phillipp, i got little problem i want to override OnAttach in all my fragments, to communicate with my mainActivity but like chatGpt sad "It's not possible to override onAttach using extension functions because extension functions only add new functionality to existing classes and cannot override existing methods". Do u know some solution better then override it in all my fragments?
I'm sorry.. I didn't understand what you tried to teach with the elimination of the BaseActivity..
You said it would be bad when we change the code inside baseActivity because it would reflect everywhere and create strong coupling. But wouldn't the same thing happen with an extension function? I mean if we change the code inside an extension function, it would be changed in all the places where it is called.. right?
You can still better separate your extension functions, create overloads and put them in different files. If you put all that in your base activity, it will grow to death at a certain point.
Also a file with extension functions has a clear purpose. You know what's in there. You don't know that with a class called BaseActivity.
@@PhilippLackner Got it. Thanks!
Really your videos are increasing my code quality.... Hopi g for more videos...👏
Hi brother. I have one question ?
How to restore fragment state of previous fragment when back press in navigation components
Hey Philip, I recently faced an issue testing with coroutines and used the exact same approach that you provided somehow.
This is a really good observation my friend😌😌 Will help me lots
Great video bud..I needed this right now!
The 1st tip doesn't really solve the tight coupling or having methods placed in a separate file where they are "hidden"... It's the same with an extension function class, you have to navigate to it to discover all those "hidden" methods...
Hi Phillip, please upload how to use flow with internet monitor
You cant say using BaseClasses is an anti pattern , i have used some BaseActivity and BaseFragment and BaseViewmodel which makes life very easy for me , you need to know how to structure your Base classes
I've written that in another comment:
If you have a base activity that has a clear purpose (and only one!) and also clarifies that purpose in its name (so it's not called BaseActivity), then this is fine.
Most often, that won't be the case though.
@@PhilippLackner Not always though , We can have BaseClasses which remove all boilerplate code , I always use BaseViewModel which expose LiveData/StateFlow and the implementation overrides it as MutableLiveData/MutableStateFlow because i absolutely hate that private _MutableLiveData / public LiveData pattern, BaseFragments/BaseActivity which connect the dagger components . etc etc
Totally agree with A Abishek. There are instances when you're designing for inheritance because you want to have protected visibility. The suggestion to use Kotlin's extension functions makes it public for any class. In the case of the video, it would be a public method for any Activity.
This issue becomes even more compounded when you are developing a library/SDK where you have an implementation that is specific to the domain of that library/SDK but then resorting to Kotlin's extension functions would expose it beyond the original domain. If that library would break or refactor that implementation or the method signature, this is going to be a compile-time issue for the client project that has imported the library/SDK.
I think Instead of using Base Activities and Base Fragments, - besides Extension function - we can use Strategy Pattern because requirements change over time and our code must be ready for it. == Open-Closed Principle && Favor Composition over Inheritance
Thank you very much for your explanation! I just wanted to ask about modules. Like..I have services (actually, they are repos when you think about it...) that read fro CSV. Aand...I don't understand why should I use any scope other than Singleton? Let's say, I will use ViewModelScope (if there is one, I don't remember). So as I understand, with every new ViewModel instance new instance of repo objects will be created?
If that's true, why would I need that? Won't it reduce performance by more frequent garbage collection?
What am I missing? What scopes are needed for? And thank you very much once again for your content!
Making everything a singleton would be bad since the stuff will always stay and occupy memory, even though it's not used.
@@PhilippLackner I see, thanks! After your video I started to use ViewModelScope. But I don't yet fully understand when VM is destroyed. Welp, it's a rabbithole, I guess)) New answers, new questions!
@@go_better its destroyed when you leave the screen it's bound to by pressing back
@@PhilippLackner is it only about activities or when I switch fragments in FragmentContainerView too?
Thanks for sharing. Philip you nailed it.
I don't agree about base classes. They help one protect from changes of framework api. E.g. some new android api sets some field nullable/non-nullable, or a package name changed.
For me, it's better to have as little direct derivatives from framework classes as possible, because you have no control on them
Sometimes without base classes it's very hard. Suppose we have 20 fragments and every fragment needs to execute something only 1 minute. Fo that I need to create CountDownTimer and after finish just exit that fragment. But it's not the right way to write CountDownTimer logic in every fragment separately, instead I can create that timer in my BaseFragment, start it in onCreateView(). After this I don't need any single line of code in my 20 fragments, I just need to extend BaseFragment.
But I'm also agree with you, because in some cases like toasts or similar things are bad practices and no need of base classes in that case.
No, count down timer logic does not belong in a fragment. Put that in another class, make it a singleton and observe the value in all 20 fragments
@@PhilippLackner Why to make it singleton if I don't need it for my whole application lifetime? Maybe in some cases I won't use any of these 20 fragments. And either way I need to put the observe logic in all 20 fragments.
@@haykmkrtchyan7093 yeah or scope it to the activity if all fragments share the same one. If you want to share the same timer instance between multiple fragments, that must be the case
@@PhilippLackner Understood. No they don't share the same instance, I can have like 2-3 visible fragments at the same time and they run their own timers. Just to prevent code duplication I used base fragment. I understand your point too, if there will be bunch of code, it will be hard to maintain))
I have a question regarding the first issue which is "using base classes". What about such a case where we create base class to handle hiding keyboard whenever we push new fragment. Is that ok or do you have better solution for this, cause idk if there is a case in which we do not want the keyboard to hide
You can as well just make the hide keyboard function an extension function
Starting activity inside recycleview adapter without passing context because according to my knowledge passing context is a bad practise as it leads to memory leaks then what's the solution to that problems. Correct me if anything wrong
There's no need to pass context to adapter, you can get it from views in ViewHolder. I would personally not start another activity inside adapter and handle it inside the activity/fragment which uses the adapter.
Create an interface with a function name it navigate or whatever, let your activity implement the interface then in adapter constructor define a parameter of type the interface you created. When you click ab utton in your item just call the fuction from your interface and also you can pass the item the postion you clicked
Can you not just make the function external to the class in any other language?
why inheritance is anti pattern?
I don't think so base activities or base fragments are anti pattern
In my current project I'm using my base fragments to inject dependencies which are required in every fragment and also helped me a lot and for singletons we can write wrapper classes too to mock these
And like you have mentioned methods like showToast()
For these kinda functions we can make extensions for these like for registering subscriber of event bus etc.
Same case for base adapters we can make generic base adapters from where we just have to return view holders
It will concise our code for recyclerview adapters
And if at some point in your project you have a fragment that doesn't need that dependency? Or you end up that you need to change the dependency for some fragments? You only have the option to change it for all fragments or other fragments will get access to the dependency even if they don't need it. This coupling is something you want to avoid. New people who will see your normal fragments will have no clue that there is actually an important dependency in your base class. It doesn't have a responsibility and therefore shouldn't exist
@@PhilippLackner you are right Phillip we were working with Google on ONA Library few days back even google don't have base classes for that projects
@@PhilippLackner and hats off to you bro♥️ seriously I feel very happy after watching your videos that their is someone who loves to work with latest frameworks and libraries
I saw these days mostly people are teaching android on old techs and I think this is the platform where they can upgrade their skills according to new era of android
@@syedovaiss thanks a lot, glad it helps!
@@PhilippLackner you're welcome dude
According to you baseActivity is antipattern and the reason is just a toast. Actually I never used baseActivity for a single toast. You can achieve a lot of functionality through base activity. What if you want to do some work in oncreat of every activity. Base activity comes to rescue.
This was just an example, of how to achieved small tasks, he didn´t say that you should not use it anymore
Awesome video Phillip!
thanks!
Your videos are very useful. Thanks a lot always!!
Glad you like them!
So good man, greate❤️❤️
more resources for this interfaces for testing please ???
Awesome!! Great quality
Thanks!
Excellent Video ❤
Thank you very much!
Your base classes use-case example is so poor in programming context.
Yes, such functions as show/hide keyboard, toasts, snackbars must be provided as extension kotlin functions.
But there are several cases when base classes supports you. in ex. u have very complex custom dialog system, where header/content/footer of such dialogs can be a custom views as well. At this point your extension functions (or any other programming approach beside of base classes) obfuscates the code instead of help.
very cool thank you BRO 👍👍👍🔥🔥🔥
Great Video! I wish I could have watched this 12 days ago 🙁. I had a bug with #5. I assumed that statics were eliminated after the app was terminated but of course that's not the case... I wrote up a stackoverflow question on it and didn't believe the answer I got until I saw it for my self... 😶
The video we have all been waiting for
Bro, Sorry if I am going to be harsh but I stopped your video at the first part about BaseClasses because you didn't propose the obvious solution, didn't you hear about overriding functions?, you could've just made your showToast() an open function with a default implementation, and say you want your LoginFragment to have a different implementation, so you override it there and none of the other sub classes of the BaseFragment is affected.
Base classes will still remain an anti-pattern since they violate SRP. Else, they wouldn't be called BaseActivity, BaseFragment, etc.
Why inheritance is an anti pattern?
I don't say inheritance is an anti pattern, I say base activities are
Thanks for the tips..
Sorry but you really lost me at the dispatcher part. For starters you don't use any dispatcher other than main in your ViewModel. And to change that in you tests you can use setMain from the coroutine test library. And in layers below that you can just inject the needed dispatchers in the constructor so you can change it whenever you want to. It's time people get past this notion that you need to write worse production code just so as to provide testing hooks since, you know, that's also an anti pattern.
No, not really, I disagree. You don't always use the main dispatcher in your view model. Your viewmodel contains your business logic and could therefore contain long running and CPU heavy
tasks which use the default dispatcher. If you then need to test that function and control the coroutine, you have to replace it with a test dispatcher.
@@PhilippLackner You have repositories for business logic. ViewModels should only be used for state management. Not that you can't put business logic in there but the fact that you might need to use separate dispatchers to do so would suggest that it's not a good idea.
Amazing 🔥
Thanks 🔥
Perfect video💯💯
Thanks 💯
big thanks
You're welcome!
Thank you, really good video
👏👏👏
I keep referring you to my friends and they keep thanking me
Excellent video
Thank you very much!
Superb:)
The first one i think isn't an anti pattern.
The real antipattern is using Android lol.
How to upload data to firebase using jetpack compose
Inti-Pattern 5. When MainActivity died the whole application will stop working and also coroutine...
Is it true that the Germans count with their thumb?😀