 Good morning everyone. I'm Shriram. I work at Facebook. I work as Android UI engineer My day-to-day job is to create Android UI widgets that will be used by different products inside Facebook. Yeah Sure So today I'm going to talk about under abstract UI concepts These are some techniques that you can use in your apps when you are ran out of ideas and optimizing your performance So if you look at apps in the Play Store, most of them are giant list views. They show a lot and a lot of stories Here is an example where Facebook is Showing a lot and a lot of stories. It could be from a user. It could be some forum It shows a title Reflecting either the username or the page name and some content and net and so on This is the Strava app here again It's a set of multiple stories and then this is dig and here is a Gmail So typically we all deal with list views and list view rows The height and the contents inside each row varies. So how do we optimize or how do we change the way? We think about these rows so To get a common base, let's define some feed story as something like this We have a profile photo some username some piece of text and then some secondary row showing some more information and a row of buttons We all know how list view recycling works So let's say we have seven items that can be shown in the screen as the user scrolls The items that go away from the screen or move to a recycle bin and new ones are either Coming back from the recycle bin are being inflated the set of steps that happen here Is vaguely like this so the list view calls its adapters get view method Which would inflate a new view and then it would do a measure pass and the view that was returned The layout pass and then add this view to the list view now the measure pass is pretty expensive If you have a huge view like what we saw now Then it would have to measure and sometimes remeasure the same view again and again, which is not even effective The place where this exactly happens is let's say we have this huge feed story And then the user tries to scroll this particular app when very small portion is seen At the bottom it tries to inflate the next row, which is really huge and so much measure pass happens To avoid this We can imply something like breaking the rows instead of treating one big story as one row in your list view You can split it into multiple rows. For example in this case you can treat the header as one row the Connect portion as the other row and then the Secondary icons as the third row and the footer icons as fourth row this way We split the way and write Recycles all these rows. This is not Just good for list views. This is also good for the Recycler view introduced by Android. So Now with the same Scrawling at this point when it has to inflate a new Feed story it won't inflate the entire feed story But it would just inflate just the header view that is needed for that particular portion that way That way we reduce the measure happening on these views Here's some example code that can achieve this in my case. I'm defining four different rows pair feed story this piece of code resides inside the adapter and The view type code written by this adapter is for and the view type depends on that particular position that the adapter requires so my get view would return and bind model just Required for that particular piece of the story and not for the entire story So what are the advantages of doing something like this as I said less binding time and less measure time We also reduce the view depth think of having an entire feed story where you have linear layout of linear layouts are relative layouts Here the connect portion can be just one text view instead of it being inside another linear layout the next approach you can use is Going beyond what and it provides like instead of using linear linear layout or relative layouts You can use custom view groups. These are really helpful if you are layout is pretty complex So here is an example. The first one is from Facebook. This is the normal header You see in each and every post this one is from Strava the Common thing is they have a profile view some title text and some sub title text So let's define something like this and see how much time it takes to measure this particular view if you use standard Android components So here is the same thumbnail title subtitle and a small menu button We can use a linear layout of linear layouts in this case we have the title and subtitle inside a vertical linear layout and This along with the thumbnail and the menu icon are inside a horizontal linear layout So I logged how much measure pass happens for this particular case inside Android. This is what we get It basically tries to measure how much time it takes How much space it needs for the inner linear layout and then measures it again clearly the title subtitle is measured twice, which is not really good because The text views are the ones that are going to take more time in your measure pass So we need to optimize on that. We can always also use relative layouts So in this case all the elements in this particular view are placed relative to one another In this case subtitle is placed below title the Thumbnail is always on the left and top of the view and the menu is on the right and top of the view By logging The measure passes. I found that it takes It measures every view twice, which is again not needed at all So if you had to measure it ourselves, if you had to design this particular thing ourselves the way we would do it is We would place the thumbnail first We know how much space it takes and then we would measure the menu button We know how much space it takes. So the remaining space is given to the title and the subtitle to measure so In this case every single view is measured only once this cuts down the measure pass by half So this is another technique which you can use To reduce the time taken during binding in your list views Here is how you achieve it in your measure pass You try to measure each and every view individually by yourselves and that provides a lot of helper methods to do it But sometimes you would have to overwrite few methods. So in my measure I'm measuring the thumbnail view first and based on how much width it takes. I'm measuring the Title so in line number 14 you can see that I'm adding the width constraints to be the measured width of the thumbnail This restricts the view that this restricts the width that the title can take This only shows example for thumbnail and title, but you can extend it for subtitle menu and so on and then All those were calling this particular method measure child with margins the default implementation of Android uses padding When you call this but in our case We Can you hear me? So we can use measure child with margins or to achieve the same The idea here is we create measure spec for individual views and then called child at measure which would measure individual views this way This is the approach With it with this approach we can measure individual things ourselves So if you had to do so we saw how much measure pass it takes to do linear left of linear layouts, especially with weights If you had to do the same thing here You would be calling measure pass again and again in this case that we can go start with the thumbnail measure it and Give the remaining space for the title We can measure the content portion separately and then we can measure the individual button separately So for example in the last column we can say that Instead of saying oh measure let the buttons take whatever space it needs and then enforce saying it should only be the 50% of the width We can Say the buttons to take 50% of the width the first time we ask it to measure It's not like you shouldn't use this approach where the breaker rows are you should You cannot use this with big break the rose approach If you want you can apply both the approaches together for more performance when the only problem with this approach is There is a bit of problem with code maintainability only the person who wrote it sort of knows like where he plays Whatever things because this is not as descriptive as XML. So otherwise This can cut down a lot of cost that you would incur by using standard Android widgets The next topic is about the sub views that we use in our in Android, so First we saw about a giant story. Now, let's move down to the text views in those stories So There are view groups like the linear layout or little layout and all the stuff which can have One or more views or view groups in it the popular ones are image views and text views image views show Drawables in them. These are more like sub views. The reason being they cannot have any interaction from the user You cannot tap them. You cannot have click events. You cannot have touch events on them Everything is controlled by the image view Similarly, the text view has a text layout. You can create text layouts It's not pretty simple as creating a drawable, but still layouts are more effective if you want to use them As a piece of trivia Gmail found that it's not effective to use text views So the entire Gmail app uses text text layouts instead of views same goes with Twitter and Pinterest So what are these layouts? This is you can think of them as Drawables for text views they contain all the information that you give to them Like whenever you call set text it creates the layout and it contains all that particular information in them it also contains information about the spanables it contains information about image spans and so on and It also has the same method as drawable. You can call layout or a draw to a canvas and it will draw to the canvas So why do we need to worry about layouts when we have text views? so again back to this view recycling when The view gets recycled it moves to the recycle bin and then comes back and in your get call you keep Setting the text on this particular text view every time you set a text on this text view This is what vaguely happens in your set text. It sees Should it do a relay out if it needs to do a relay out it creates a new layout Think of a scenario where the user scrolls down a bit and then scrolls up a bit and then scrolls down again He goes through the same set of rows back and forth again and again We are not recreating the views, but we are recreating the layouts again and again Which is costing us so much of memory allocation so much of object allocation and stuff So instead of doing that we can cache all these layouts. We can take those layouts Put it in a cache. So in my set text I am passing a key based on the particular row that I want to use and Using the key I'm trying to see if a layout has already been created for this particular text If it has already been created I'm using that layout if not I'm going to create a new layout and in my draw I'm just calling him layout or draw this will have the same effect as what text we will do it for you so again the advantage is less object creation you have more control over the cache and The machine cost is saved because it's going to be measured only once the next time you can just Get them a width from the layout. You don't have to recreate more layouts again and again But there are a few things we need to watch out for what if there are orientation changes if it changes from portrait to landscape the with Available for the title a subtitle would increase now in which case we have to nuke the entire layout cache and rebuild everything from start And similarly with local changes as well Again back to the same slide. We are drawing everything to the canvas Studying with ICS they introduce display list which basically caches all the GPU commands Which is really effective because it caches the commands and then replace them back Which is a huge performance win, but this is not available pre gingerbread. What can we do to achieve? Somewhat similar performance in gingerbread phones and it has something called a picture drawables The idea here is you cache all the commands that you send to the canvas and then replay them back So the same code I changed to use picture canvas the picture Is something that can record all the calls? You give it to a canvas In my on draw call if nothing is recorded already. I am creating a new Canvas so when I start a recording like mpicture.begin recording it returns me a new canvas I'll make calls like super.draw or mlayer.draw is passed to the picture canvas and The next time this particular view gets invalidated. I'm calling mpicture.draw. This is like the cached version of commands and The this approach gave like So without this approach it took like 18 milliseconds for me to render text with one particular example And with this particular approach it Got significantly lower and it just took three milliseconds. So this is another approach that you can use one caveat here is that You can use this only with software rendering model. Hardware rendering model doesn't support picture drawables The next thing is about images Our apps have a lot and a lot of images a lot and a lot of clips For example, this is Facebook app and these are the list of Icons shown in this particular screen. This is very very less compared to the whole lot of icons we ship as a part of the APK So how do we handle this and Android provides? I mean a web introduce this concept of sprites instead of Downloading one image after another sending a request to the server making a connection in the downloading the image You can download one giant image with all possible Images in it and then draw portions of it in each and every image view Android has started doing this they call it texture atlas. It's the same name in open GL world as well Here is the texture atlas used by standard Android and Jelly Bean This gets generated every time you put on your device and every time and it has to draw a piece of this It uses the same texture it binds this texture and then draw portions of this So why is this actually needed or why is this going to give us performance wins? So Before Jelly Bean if we had two buttons in our app like this It would go View after view it would draw the background of first one and then draw the text one It would go to the second button drives background and then draw the text after Jelly Bean They changed it where the batch and merge these Commands immaterial of the view so all the backgrounds will be batched and they will be drawn first And then the text will be drawn next the reason is these two backgrounds share the same texture so they bind the texture once they draw them first and then the characters usually had shared the same texture if they Have the same font size color and so on so they bind that texture and then they draw that text This reduces the number of commands that they pass to the GPU So if you are going to use something like sprite then you are going to bind the texture once you are going to draw all the Images in one single draw command instead of passing like 10 15 different draw commands in in case of the Facebook screen And how hard it is to implement something like this on pre Jelly Bean because this is something you get it for free in Jelly Bean How hard it is to implement in pre Jelly Bean is this simple Can us have this a method called draw bitmap in this You need to pass in the bitmap that you want to use and then the next two arguments There are the source and the destination rectangle the source rectangle is that patient that portion in the bitmap that needs to be drawn on the screen and the destination is The piece on the view that it should be drawn and and I would map the source and the destination and then would draw that particular bitmap to the destination so This is a bit more complex thing. It uses the same technique and line number line. It's the same API call the Here I'm setting the coordinates on the view with top left right and bottom and in my draw call and getting the destination rectangle and then The destination rectangle here would not have the padding Maybe if you want offset something or if you want to have more customizations You can put anything in that destination rectangle by calling this it uses the same bitmap and then draws that particular portion. So Will this have any effect post a jelly bean of course Yes, because you're still having one single texture. You're binding the same texture again and again and then drawing it So you would see performance improvements Even after jelly bean with this approach so again the advantages you are Binding one single bitmap and sending less commands to the GPU Next is collecting thing. We all know this was introduced in a lollipop this is a Cool feature if you want to reduce the number of images in your APK So the need arises for something like this say the tab bar icons have The disabled state enable state and then the selected state clearly We have like three different images that we need to ship with every single glyph That increases the APK size a lot How can we mitigate this problem or how can we reduce the amount of images we ship in our APK? so You can use something like a color filter that can achieve this for you. I'm taking a black Glyph, and then I am applying a color filter to get the gray one And it provides various color filters like ported of color filters lightning color filters and so on the ported of is pretty easy to use and That would help you a lot in this particular case the way it's basically an alpha composting method that means Whatever you want to draw now you say you give it an operation saying This is how I want to draw this particular thing onto whatever is already available in this case The destination is the purple blue circle The source is the red square So when you are about to draw the red square you can say like I want to draw the source or the destination so The red square will be drawn on whatever is already available on the canvas Or you can say destination over in this case the destination was this purple blue circle That will be drawn below the Actor what is what you want to draw? But in case of color tinting what we need is source and more what this basically means is draw pieces of source that Overlaps with whatever is already on the destination so wherever you see black parts on the canvas or wherever you see Now non-zero alpha parts on the canvas then you could use a different color to Redraw it so If I have say a black icon like this and then I use a gray color and then say use a source and Ported up more Then it would just shade that portion with a gray color So clearly you can use one single cliff and then use different colors That way recreating all different states So this is how we do it. It's again a very small piece of code You create a portrait of filter filter with the tint color the mode is sourcing and then you set this color filter on the draw But if you are using this inside an image view you can just set the color filter on the image view itself but Will it scale for state changes or how hard it is to manage state changes Say if you have a state pressed if you earlier if you were having Icon for a press state and now you want to simulate the same thing Would you have to monitor touch evens and so on actually? You don't have to monitor state changes because Android provides draw the state change before that Let's say we define a selector like this here I'm defining the disabled state to be gray enabled to be white and the selected state to be blue I'm going to use this color state list with my view whatever that I'm implementing In my drawable state change. I'm trying to get the state using a drawable state and then The tint color is obtained from that particular color stateless But that color tint color. I'm creating a new portrait of filter and I'm applying that color filter To this particular image view thereby You can reduce quite a lot of images in your app You can also come in come in this with sprites because again a sprite is going to bind one single texture and then you can This is a done at canvas level so This will work cleanly with sprites as well and that's pretty much it for today. Yep, right You're basically forcing the app to use more battery and CPU The these are done at a GP level and I would I don't think this would take more Battery because these this is something Android provides out of the box so This is not like a complex operation Especially if you if you think ported off is a pretty complex operation This is like a standard window composting operation that is available On any windowing system and this is a pretty basic operation To for it to compose a different views and so on so this is not CP intensive operation which particular approach in this Oh, the ported off mode that you told about. Ported off mode is available Since early days of Android So to give some more context if you want to create rounded bitmaps and stuff Using ported off mode is the most effective solution than having two or three layers or applying a mask in a different way and stuff so This is I mean, I would say like ginger starting with gingerbread you can safely apply this approach