Fragments: Past, Present, and Future (Android Dev Summit '19)

[Music] thanks for coming my name is Ian Lake and I'm Jeremy woods and today we're here to talk to you about fragments not just fragments of today but fragments of past present and we're gonna give you a little sneak peek about where we're going with fragments in the future so starting with the past fragments were introduced in Android Honeycomb API 11 but we don't really talk about honeycomb so we'll move on to what they're originally supposed to do and fragments were really designed from the beginning to kind of be micro activities I remember way back in the day when everything was in your activity and fragments were really kind of that very first step into moving code out of your activity and into something smaller but that also meant that we inherited a lot of the API service that was inherent in activity so that means that we got things like all the action bar menu stuff because there wasn't something called toolbar yet it also meant that we had things like context menus which would actually use context menus anymore third thing but they don't really need to be on activities or fragments per se they could be on views themselves it also meant that we got a lot of custom hooks so all the things that were normally just sent to your activity are now also sent to your fragment for instance things like on activity result that's pretty useful people use that right things like permissions when Android M came out and we added runtime permissions of course fragments got it because activity got it and also things like on multi window mode changed or on picture and picture mode changed and these are all kind of things that we just got kind of for free being fragments and being this idea that there are micro activities but when you think about it a lot of these things aren't specific to fragments it would be nice if anything could get these kind of all backs so we've kind of gone through this kind of existential crisis I'm kind of moving away from this idea that oh it's like oh just because an activity can do it a fragment can do it so that kind of leads us to today that was 2011 and we've tried to come a long way since then a lot of this is really trying to restructure what is our goal for fragments and some of this is really just being a focused API service really making sure that it's just the core piece that you need with predictable sane behavior that means no surprises no things that just randomly don't work but it also means we don't want to break existing consumers right and that means binary source or even behavior compatibility now along the way that does mean that we do have times when we introduce a new alternative new API that is predictable and nice and we deprecate the old API because we can't actually remove it until we have a good alternative that gives you something much better to work with but the idea is that we do want to release a 2.

0 at some point where as long as you're not using the deprecated API so if you're all on the good new API surfaces then it'll be an easy transition over and we'll be able to cut out a lot of code out of fragments to support these kind of more legacy cases so what are we doing to get there well the first part of providing kind of a sane API is a testable API if you're writing code that you can't test that's no good and if we're writing a library that you can't test code written with that library that's not going to work either so in 2019 here we really want to make that better so we have a fragment testing artifact now that offers fragment scenario this is really a way of kind of testing just one fragment in isolation and we worked really closely with the Android X test team so this is actually built on activity scenario which means it works for instrumentation tests and works for robolectric tests now we wanted to make sure that this had kind of a nice small API service so really has like one main method of on fragment which is takes a lambda gives you the fragment instance that's available already and it also kind of gives you a lot of the hooks that you need that makes it really easy to test things like life cycle and recreating your whole fragment so what does this look like well it's actually pretty easy you create your scenario using watch fragment in container which will do all of the creating your activity adding the fragment moving it to resumed and then we can just do a special test right just say on view click it and the fragments hierarchy is already there it's already ready and then we can use on fragment to then check our internal state check to see did it actually handle the click correctly for examples if you're doing more complicated things right if you want to check how when you move through lifecycle states you can just call it scenario move to state and move it to started or created or resumed same thing with actually testing recreation by do I use save and restore my state properly just call recreate you can check your state before we create you can check your state after we create and that's all you really need to do so the other bit is we have this recreation thing well that's really just one of many ways that you need to instantiate a fragment right so we also have cases where you're adding a new fragment in the first place you need to instantiate a fragment to give it to fragment manager and but also we have things like fragment scenario you need to inflate the fragment to add it to your UI for testing right so we wanted one way of doing this and this one way is fragment factory so this gives us kind of a way to now finally be able to do constructor injection into your fragments and kind of move away from this requirement that you need a no argument constructor now you can actually build something that does all this for you so what does this look like well a simple fragment Factory it's really just one method it's to initiate where you're giving a class name and it's up to you to load the class so super dunce and Shea will just use reflection call you're no hard constructor but really you can do anything you want with this if you watch the opinionated guide to dependency injection this is the kind of thing that we'd love to do for you at some point so you don't have to write this but even right now if you just pass in arguments into your factory then you get a really easy way of this passing those on to the fragments that care about them by using constructor injection here so then all you need to do in your activity is just call fragment factory and set it equal to your factory verbally before super dot on create because that's when we're going to be reinstating fragments now the other bit that we want to do to kind of fix up all of this you know consistency everywhere is sorry is all the other places that you have fragment creation so if you're doing a commit and you're adding a fragment now instead of having to do this whole instantiate and doing all that constructor injection you can just add it with a class name here we're using the collin reified version so now will delegate to your factory and now you have one code path for doing instantiating here for the very first time when you're adding or replacing a fragment similarly when you're doing your fragment scenario you just pass the factory it could be a mock factory that you've created just to give mock dependencies or it could be a real factory if you're trying to do more integration test style work so i'm going to pass it off to jeremy to talk about another area we work at consistency so one exists see we found between adding the fragment to something like say a frame layout versus using the fragment tag as it turns out the fragment tag has fragments uses a totally different system from fragment transactions to provide consistent behavior we built fragment container view as the one true container for fragments fragment containing view extends frame layout but it only allows fragment views this means if you're not a fragment you probably using this it also carry replacing the fragment AG when you add the class on or Android name attribute so in this example because fragment container who actually does use the fragment transaction under the hood you don't have to worry about you'll have any issues we're replacing this fragment later problem container view also gave us the opportunity to address some animation issues specifically an issue with Z ordering of fragments so here we can see the framelit in the frame layout example that right entering fragment instantly pops onto the screen what's actually happening here is the entering animation is sliding but it's underneath the exiting animation fragment container view ensures the Z ordering so we can actually see the sliding in the sliding animation for the entering fragment providing predictable same behavior across all API levels another long-standing issue we had is handling the system back from the fragment to address this we had the own back press dispatcher instead of adding a fragment only API now any component can handle a back event via a new API on the base activity class component activity ideally you can check the own back press dispatcher for testing purposes but here we're going to show you how to use it in code so a fragment would grab a dispatcher from its calling activity or from its activity and then we'll create a callback here we create that callback using the cotton lambda and we pass it this and we can pass the fragment because the fragment is a lifecycle owner so for example in your code the user presses back and then we call show confirm dialogue on the back button is pressed and then the user will say they want to exit anyway we'll disable the callback and then we'll use the dispatcher to actually do the back press so no new fragment API instead we just take advantage of the existing integration between fragments and architecture components so an architecture components are something we want to leverage even more going forward so for example it should be easy to get a view model from your fret for your fragment and here we create the Kotlin property extensions so you can get a view model at the fragment level the nav graft level or the to be level so your view model is always properly scoped and you have the tools to provide that we're also leading to the lifecycle as well for example instead of using the custom lifecycle map that of set user visible hint you can now just use regular lifecycle methods when you're adding fragments to a viewpager one adapter and so this is currently how few page of two works and only that your current fragment will be resumed back to in great thanks Jeremy that was a really good rundown of kind of what's available right now so fragment 1.

1 had a lot of this Fryman container view is in fragment 1.

2 which is an RC one as of yesterday but I the other thing is I want to talk a little bit more about where we're going have longer-term there's a lot of other things that we want to do so I'm going to share a little bit of a preview of some of the projects that we're working on but of course this is out yet this is all subject to change pretty happy with where this is all going but it's not something you can play with right today so the first thing is multiple back sex some of you may have heard of this it's a thing but really the some of this comes down to just that existing legacy on Android so on Android especially I'd like the activity level it was always a single stack of activities right and fragments just ended up inheriting kind of that same structure where the only things that are saved are the things that are on the back stack and we really want to move to a model where we kind of support both not just the single stack approach but also the multiple stack approach and really that just means that we allow you to save the state of fragments that aren't actually visible on the screen without losing their state so this is some of the cases that came up was really like bottom nav things like navigation views and we have a sample app right now that uses kind of a little bit of a workaround say work run it's some some nasty fragment code and really we would just want to make this really easy a kind of the fragment level so kind of the approach that we're taking is kind of that same ability where each one of these tabs can actually have its own stack it has its own state so as you swap between these it's really more about saving and then restoring a different stack right and we're taking care of doing all the state restoration and state staving as you go from stack to stack the other bit that we want to work around is around returning results so we've heard a lot of you know information where you're like how do I talk between fragments right how do I talk between anything on Android as always kind of you know there's lots of different ways of doing it some better than others and it turns out that the fragment API is we have right now are not great so we have this whole like set target fragment API that allows you to connect one fragment with another and basically just keep a hard reference to another fragment but it basically does nothing for the lifecycle of what that other fragment is so if that other fragments on the back stack it's not stuck it's actually stopped right it's not started and if you actually talk to that fragment and it's trying to do like fragment transactions and stuff that's going to fail because you're not started so we really don't have any kind of guarantees around like wait what state is that other fragment actually going to be in additionally we add like this you know idea that like oh you can use on activity result and I'm like intense from fragment to fragment like that feels kind of weird like we don't really need to be reusing some of these API surfaces for callbacks so we're really kind of looking at this more holistically not just fragment to fragment but also things like startactivityforresult can we do kind of the same kind of API surface for startactivityforresult for fragment to fragment communication from navigation destination to navigation destination can we provide kind of a common API that all these things can time to talk up so that when you're building callbacks it doesn't actually matter if it's coming from a different activity or a different fragment so that's kind of where we kind of see a lot of those api's going I'm really excited to share some of that in just a few months maybe and the other thing is and something we've constantly heard feedback on on fragments is lifecycle like that's hard right well it's like doubly hard with fragments because fragments have two life cycles the fragment itself has a life cycle which is when the fragment is actually attached to the fragment manager until it's removed from the fragment manager and gets destroyed but the fragments view has a totally separate life cycle where when you actually put something on the back stack its view gets destroyed but the fragment lives on so crazy idea what if they were the same so we have this idea or what if when the fragments view was destroyed the fragment was destroyed at the same time and then when we want to recreate your view we recreate your fragment and bringing kind of these things together saves so much complexity and means that things like fragment factory and all the savings states that you have to do anyways for cases like oh I'm on configuration change right the process death and coming back now that just becomes the default option and now we only have to test one code path of like wait what state am I in a my observers doing the wrong thing here because these switching life cycles now do rise this is a bigger change so we are looking at making this kind of an opt-in kind of API at the fragment activity kind of level so everything in that fragment activity would all move to this new world where we have a much more simplified life cycles case so really looking forward to releasing all of these things and we'd really appreciate it if you can talk to us in the sandbox if you've gotten a feedback also using the issue tracker Google comm if you have any feedback or other feature requests that you'd love to see in fragments thank you [Music] you.


See More Android:

Hãy bình luận đầu tiên

Để lại một phản hồi

Thư điện tử của bạn sẽ không được hiện thị công khai.