Fragment Constructor Injection with Hilt and Navigation Component

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so why is constructor injection the preferred method of dependency injection over its alternative which is field injection at pretty much any circumstance when it comes to android development the answer to that question has to do with testing when you're writing tests you're writing instrumentation tests you're writing unit tests whatever the type of test it's always better to know what dependencies you need for any given object when you're writing the test for that object so like if you're testing a repository it's much easier to know that the repository requires you know four objects as opposed to having to open up the repository and see that oh i have to make sure that this object is ready i have to make sure this object is ready if they're required for the construction of the object or in other words when when they're required uh in the constructor then you already know what it needs and it's much more convenient to build the test for it so much like all of the other classes that you are probably familiar with building tests for like repositories view models any kind of random data sources any random classes really it doesn't matter there's also android specific classes that are also nice to do constructor injection with and the one that i'm going to talk about in this video is fragments so most of you probably think that it's not even possible to do constructor injection with fragments but it actually is there was an update um i'm not sure when it was maybe i'm gonna i'm gonna throw it a number here because i don't know the exact number it was maybe six months ago the android team added this new class this new fragment factory class that we could that basically enabled us to do constructor injection with fragments so in this video what i'm going to be doing is using that new fragment factory class to do constructor injection to a fragment and we're going to see how this is all handled with hilt so i'm going to use the new dependency injection framework built on top of dagger which is hilt and i'm going to be showing you how to not only just do it with a the plain old you know begin fragment transaction support fragment manager fragment transaction way but we're also going to be doing it with navigation components because it's a little more tricky but i think you'll find it's still pretty straightforward by the end of this video okay so the code that i'm starting out with here is from a video that i just did yesterday i'll put a link up here to it but if you want a link to the source code it's going to be down in the description of the video or you can go to my github go to dagger hilt playground it actually says player ground but that is a typo it should be playground go to the repository and check it out so you can just like get the repository check it out if you want or just make sure you click on the branch fragment constructor injection that's going to be the end point code for this video if you want to look at the same code that i'm looking at right now at the start of the video you want to check out the branch basic mvi repository pattern that's the code that i'm looking at right now and by the end of the video it's going to be fragment constructor injection so let's get started so as you saw in the previous video which is the one that i'm carrying on from we have a single activity i'll actually launch the app just so you can see so the app launches you see a progress bar it pulls some network data it caches that data and then it displays that cache data in the ui there's just a single activity in a single layout which is activity main so here's activity main you know just a progress bar a text view nothing fancy we got a bunch of packages here again check out the previous video if you want to know where all this stuff is coming from but the fragment constructor injection stuff really has nothing to do with anything else that we've done so far so you could just follow along even if you didn't watch that previous video so main activity uh pretty straightforward just like you know getting the view model getting some data from the view model doing all the stuff pretty basic again watched the previous video so now we are going to set up for this new fragment that we're going to create and do constructor injection on that fragment so the first thing that i'm going to do here is i'm going to build a new layout file so i'm going to right click on layout go to new layout resource and call this fragment main and click ok and sure i can add that to git why not and i'm just going to copy the previous layout from activity main because we're going to basically move everything that's in activity main into the new fragment and then the new the and then activity main will basically just be a container for the fragment so there is our new layout which is the progress bar in the text view which is basically just what we had before but it was in activity main now let's go to activity main and make the required changes so i'm going to pretty much empty this out so i'm going to delete the progress bar delete the text view delete these tools and i'm going to change this constraint layout to a fragment container view so for those of you who don't know the fragment container view is a new view that was created again i'm going to throw it a number here i think it was about six months ago when they created the fragment factory somewhere around there i'm not exactly sure and it was to replace the frame layout so remember before we used to we used to use a frame layout and that was used for containers for fragments and a bunch of other things it was basically it was a very robust uh very robust layout so the the fragment container view is the replacement for that and it can handle everything i can handle navigation components you know just being a general container for fragments basically everything the frame layout could and more so i'm going to give this an id of main fragment i could call it main fragment or main fragment container whatever you want now that we have the updates to activity main we have our new fragment layout now let's build that new fragment class so i'm going to right click on ui go to new kotlin file and call this main fragment and then just select class here so of course this is going to be a fragment so i'm going to extend the android x fragment class and i'm going to pass the layout up here so r dot layout dot fragment main and that should give me there we go got that in there so again for those of you who didn't know you can now pass layouts to the class extension constructor when you're building fragments that was another one of the things that was added about six months ago i'm going to say again not 100 sure on the exact timeline there that was when fragment container view was added you can pass the layout to the fragment constructor the class extension and also the fragment factory which we're going to be looking at later so all of this stuff was added around the same time period okay so we are going to add a constructor to this fragment so i'm going to add a constructor here and i'm going to have a single dependency because i want to be able to inject something it's nothing important i just want to show you that something can be injected so i'm just going to inject like a string just like i'm going to call it some string and inject some string so usually like you wouldn't be just injecting something random like this but again this is just an example i just want to show you that something can be injected through the constructor so i'm just going to inject a string just so you can see it now this fragment clasp is pretty much ready to go because we are passing the layout to the fragment up here before you used to have to insert uh on create view and you would have to uncreate view yeah this one and you need to pass the layout to the super and you know tell what layout you're using we don't need that anymore basically it's all good with this this layout passing through the constructor here so i can delete all this stuff and our fragment is pretty much ready to go now keep in mind we are going to change some stuff in this fragment it's not complete basically by the end of the video i'm gonna move everything that's in main activity over to that fragment class but for now just just leave it as is and this is gonna give us some warnings because we've changed the layout but again just ignore that we're gonna fix that stuff later now let's build the fragment factory so that we can pass dependencies through the constructor of this fragment so i'm going to go into the ui package create a new kotlin file and i'll just call this main fragment factory and this is going to be a class so add that to git doesn't really matter this is going to extend the fragment factory class and i want to initialize that now i am going to be providing this through hilt so i'm going to annotate the constructor with at inject and get that get that import there and tab this in just so it's kind of cleaned up and through the constructor of the fragment factory you need to pass all of the dependencies for any of the fragments that you have so in our case the only dependency that we have is some string so we are going to need to pass that as a constructor argument to the main fragment factory if we had more dependencies like if there was i don't know private value some object and this was like some other object maybe we had private value i don't know just just for example state maybe we're passing like our main repository here if all of these objects were being provided into our fragment class we would also need to provide those to the factory because we're going to need them when we build the fragment which you're going to see in just a second here so just to make that really clear and also if you had more fragments like if you had main fragments if you had um like main fragment 2 main fragment 3 whatever your fragment name whatever dependencies that those fragments required you would need to pass them to the constructor of the factory that's building them so just just to make sure that that is really clear so there's the dependency the only one that we need because all we are passing is this one single string now i'm going to insert a function so ctrl o and get the instantiate function and this function will be responsible for building whatever fragments this factory is responsible for so i'm going to write return when the class name and open this up and just do main fragment and then do class dot java whoops.java dot name and there's a couple ways you could do this but this is just the way that i generally do it if you have a different way that's fine too so now i want to instantiate main fragment and then just pass some string and as a last case we want to be able to uh return the super so just do else and then do super instantiate class loader class name so that's it pretty simple pretty straightforward nothing too exciting here the only thing to keep in mind is if you had more fragments in your project so if this this one only has one fragment which is main fragment but if you had more fragments you would have more cases inside of the when statement you would have you know however however many cases you needed to instantiate all of the fragments that that factory is responsible for okay so we have the factory we have our main fragment next let's build uh let's build the module that will provide this string because we we do need to provide this because it's being injected through the constructor here so let's go into the di package i'm going to create a new module because i don't want to use any of the old classes like i said i want you to be able to watch this video and not not have to have watched the video before so i'm going to keep everything separate and just create a brand new module so i'll call this app module this is again a dagger hilt thing if you're not familiar with that i have a dagger hilt playlist also my website if you want to watch all the videos that have to do with dagger hilt the new dependency injection framework you can just go to codingwithmitch.com go to courses up here and here it is the hilt dependency injection course it's completely free you know it keeps track of your progress you can see a little progress bar over here you can just click on this and go through the videos and you'll see it'll keep track of your progress so we want to install this in the application component again if you don't know anything about hilt i encourage you to go watch the course and it'll teach you about everything that i'm about to do here this will be a singleton i'm going to annotate it with that provides and just do provide some string because that's all i'm doing i'm just you know just returning some random string i'll just say it's some string exclamation mark so there's our string dependency i've installed it into the component now the fragment factory will have access to that through its constructor and also our main fragment will also have access to it because it's being passed to the whoops to the constructor right here so we could uh we could test this by maybe inserting on view created and i'll insert log t here so this is a template you probably won't have this in your android studio this is a template that i built just write private value tag string app debug or whatever string you want and then i'm going to print that string to the log so i can say i can say i guess here is some string and then just print that and say some string so now if this fragment comes into view we can at least look in the log and see if our dependency is being provided like it should be so to test this i can go to main activity and i will comment out a bunch of this stuff i guess i'll just i'll just comment out all this because we're going to move this into main fragment later anyway so i'm just going to comment all that stuff out and now to do the fragment transaction so to actually bring this fragment into view what i can do is i can set the factory and then do the fragment transaction so i will inject the factory up at the top of main activity here so i'll do add inject late init variable fragment factory so main fragment factory i guess i need to i don't need to annotate this with an entry point that's fine so just inserting the fragment factory and now i can do support fragment manager dot fragment factory and set that equal to that fragment factory then i need to do the transaction so support framing manager begin transaction dot replace i want to reference the container so r dot id dot main fragment container then the fragment class that i'm going to be bringing into view so i'll say main fragment class.java and then null for i believe those are those are arguments being passed and then document so that's going to do the fragment transaction that should bring main fragment into view and then we can see if that is that dependency is being provided through the factory so let's uh let's run that i'll open the log and we will take a look so i'm filtering the log on here so i can see here is some string and there it is here is some string it's some string so we know that therefore the the dependency is being provided through the constructor and it is available inside of the fragment so that's great now let's uh now let's do this with navigation components and kind of move everything into the other fragment into the fragment class so what i'm going to do is i'm going to cut this view model and move it into the fragment so if i'm moving the view model into here i also need to annotate this with android entry point so android entry point because this is this view model is being injected using hilt so i need to make sure i add that annotation now let's move everything else into here so i'll uncomment uncomment this up here grab these two cut that go to uh go to main fragment paste those down below and i want to give myself some more room here so give myself some new returns go back to main activity i'm going to uncomment all this stuff so that's uncommented that looks good now i'm going to cut it i'm going to delete all these unnecessary imports up here because these are no longer needed inside of main activity go back to main fragments and paste all this stuff in and get the imports there's a couple more imports that it looks like it needs to get make sure to get the android x lifecycle observer for that import text that's all good and then change this to get view lifecycle owner for the observer the last thing here is this is giving me a warning saying i'm using some experimental features so i'm just pressing alt enter and then getting that annotation you don't need to add that it just kind of gets rid of that warning saying yes i know that i am using an experimental feature here um this i can get rid of off of the view model all right so now everything should function exactly as it did you know at the end of the previous video the difference being that we have a fragment so now main activity is pretty much empty all it is is essentially a vessel for hosting the fragment and then the fragment has all the content so let's run this and after we run this and see that it's working then we're going to convert this to use navigation components so there's the app launching there's the progress bar and then there's the data getting pulled from the network cached into the database and then displayed in the ui and if also if i open up the logcat down here we see that hey there's our string still working correctly so everything's working correctly everything's working exactly as it was before the difference being that now we have a fragment we're doing constructor injection with the fragments and we are printing out that dependency just to make sure that we actually do see it we do have it all right so now let's set this up with navigation components so i'm going to close all of this stuff and stop the app and i'm going to create a new navigation graph so right clicking on res oh by the way if you don't know how to use navigation components i should say i have a free video on youtube so if you go to youtube.com with mitch i have a free video it's quite long it's like 45 minutes to an hour but it shows you everything you need to know to get started with navigation components so i think it's called navigation components in one video so i'm just searching navigation component and there it is right there jetpack navigation component in one video so that shows you everything you need to know to get started with this it's basically the new way to navigate android apps using fragments this new kind of navigation graph system which is way better than the old way in my opinion so i encourage you to check that video out also my courses uh pretty much all the new ones use navigation components so clean architecture all the ui testing ones model view intents powerful android apps all of these use navigation components so if you were curious go and check out those courses and see a more practical realistic example of how to use navigation components some of them are paid some of them are free you'll have to go to the website and check those out so i'm right clicking on res here going to new android resource file make sure to change this to navigation and call this uh nav main that should be yeah that's what i forgot to do so we're going to add a single fragment so pressing the plus button up here adding main fragment now we have main fragment added to our graph now i'm going to go over to the xml tab here and it actually looks like this is all fine so we have our start destination that's what i was looking for we have an id so nav main so everything should be good here now this is going to be the kind of the trickiest part of this whole video i would say coming up next so previously when using navigation components if you were injecting a fragment factory if you were just using regular dagger what you could do is you could take the fragment factory and before oncreate you would do like your you would do your inject with dagger and then you could set the fragment factory right here before oncreate was called but with hilt you can't do this so if you take a look at the hilt documentation which i'll pull up right here you can see that hilt will do the injection right here before on create and we can't get access to whatever we inject until after oncreate is called so this causes a problem because if we inject our framing factory and we don't set it until after oncreate um this will cause it the app to crash if there is a rotation because the fragment gets recreated and it won't be able to find that constructor before uncreate is called so it has an issue so this is kind of one downfall i guess if you're using hilt and you're going to use navigation components because it's going to be a little bit trickier but i'm going to show you a workaround that it's actually pretty straightforward and you should have no problem with it so i'm going to move this back i'm going to delete this get rid of all those lines move this back and we need to create a new class in the ui package so i'm going to right click here go to new kotlin file and i'm going to call this main nav host fragment so if you're familiar with navigation components you know that this the navigation components revolves around this kind of default nav host fragment thing and i'm going to extend by that class so nav post fragment so what we're doing here is we're creating a custom nav host fragment that we're going to set in our layout so normally what you would do is like you would go to your fragment container view and you would do the name parameter you would do android x dots navigation or whatever the package is and it would be like nav host you would use the default nav host fragment i don't know if this package is correct but the point here i'm trying to illustrate is that you would use a nav host fragment here well we can't use it because of the issue that i just pointed out so we need to create a custom one which is what i'm doing here and what we're going to do this custom one is we're going to mark this with android entry point so android entry point and then we can inject our fragment factory into here so latent variable fragment factory main fragment factory and then i'm going to insert the on attach method the unattached function on attach get the one that takes the context as input this one right here and then after on attach is called i want to set the the fragment factory to the child fragment manager so child fragment manager fragment factory equals the fragment factory now let's get rid of this warning so this is that experimental co-routines feature warning just pressing alt enter getting that annotation and then adding that up at the top here so here is our custom nav host fragment that now knows how to use our our custom factory so now we can go into activity main and instead of setting the name parameter to the kind of default nav host fragment that i just kind of showed you we're going to use our main nav host fragment so i need to copy the package structure so come come back to main nav host fragments copy the package structure type that in here and then just do dot main main nav host fragment now that now this knows how to use our custom nav voice fragment and therefore our custom fragment factory now we need a couple other parameters here and if you're familiar with navigation components this is going to look very familiar to you we need to set the default nav host and set that equal to true and we need to set the the nav graph so we need to tell it where to find the navigation graph that we're going to be using so at navigation and get main nav which is what we just created and that should be good let me just kind of go through this one more time just make sure i didn't miss anything of course we can get rid of this fragment factory now get rid of this get rid of all of this stuff we don't need any of that we do still need to have android entry point here because any fragments that are kind of hosted from an activity um must be hosted from an android entry point activity so we still need to have this this is something that hilt requires if you have any fragments that you're injecting dependencies into the activity that are hope that's hosting those fragments also must be an android entry point so that's why i'm going to leave that there and we have our main nav host fragment which is being set in activity main we have our main fragment which is getting our dependency so now let's uh let's run this and we'll test it and make sure that everything is working so here's the app launching there you can see the progress bar showed we get the data now here comes the the part that is going to determine if this worked or not we're going to do the rotation does it still work yes everything works exactly as before so if you would have not built this custom nav host fragment and you would have just you know injected the factory and then set the support fragment manager like did support frame manager factory and set it right here it would have crashed on rotation and that was because of the issue that i outlined before the fragment factory needs to be set before oncreate but because hilt does the inject before oncreate and it actually prevents you from using any of the injected dependencies until after oncreate which which causes that problem so that is going to be that's going to be it oh actually i guess one more thing we should check is make sure that we do get our our string printing out so i'll filter on app debug and let me actually clear it and i'll rerun it just to make sure so i cleared the log i'm re-running the app there's the app launching and there is our dependency printing out again showing the rotation and there's the dependency again so everything is good so there you have it ladies and gentlemen boys and girls that is how you do constructor injection with fragments both with the old way to navigate so using the support fragment manager and also how to use navigation components which is like you know quote unquote the new way to navigate with fragments and if you're interested in in seeing you know why constructor injection is advantageous for fragments why it makes testing easier i encourage you i highly encourage you to go to codingwithmitch.com i have many many courses on testing from beginner level to quite advanced level if i was to give you any recommendation if you've never tested before i would say start at the beginner level course the espresso beginner course and then maybe jump into the clean architecture course because it's not just about clean architecture it's about it's a very heavily a lot about testing because the the main reason why clean architecture is so great is it makes testing easier so probably over half that course is actually testing so i highly enjoy encourage you to go and check that out as always do not forget to leave a like youtube does not recommend these videos unless you tell it that yes this video was good yes this video helped me so please if this video helped you if you've never seen fragment constructor injection before if you didn't even know it existed if you maybe thought about it but didn't know how to do it this video helped you so go and tell youtube that this video helped you as always thanks for watching and i'll see in the next one you
Info
Channel: CodingWithMitch
Views: 16,487
Rating: undefined out of 5
Keywords: fragment factory, android fragment factory, fragment constructor injection, fragment dependency injection, fragment container view, fragment container view android, navigation component, android fragment constructor injection, fragmentfactory android, fragment factory methods, fragment hilt, hilt fragments, hilt dependency injection, navhostfragment android, navhostfragment example, navhostfragment tutorial
Id: lH6n4--3R5k
Channel Id: undefined
Length: 24min 37sec (1477 seconds)
Published: Thu Jul 16 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.