Latest Ext JS 7.8 is now available. Learn more

Sencha Touch: Optimizing Memory Usage

March 15, 2011 701 Views
Show

Although most modern mobile devices have good hardware specs, almost all of them are still lacking in areas like memory — especially compared to their desktop counterparts. Others either have week graphics processing units (GPUs), or the browser doesn’t properly leverage the GPU for animations and drawing. In a previous article, we looked at event delegation as a way of improving the performance of your mobile web application. Event delegation speeds up your app because it reduces the amount of memory your application uses at a given time. Of course, this is not the only thing you can do. In this article, we will look at one more technique that improves your application’s memory usage.

The Size of Your DOM

The number of elements on your page has a large effect on the amount of memory your application uses, so it’s a good idea to keep your DOM as small as possible at all times. “Heavy weight” elements like images should especially be kept to a minimum.

We do have one major advantage: due to the size of screens for mobile devices, the applications on them typically show only a small part of the interface at any given time. This means we can remove the elements related to parts of the app that are not visible anymore. In Sencha Touch, this particularly applies to things like popups, modal windows, and cards in Panels and Carousels. So how can we leverage this knowledge when writing our apps?

In Sencha Touch, there are events that fire when the visual state of a component changes. For example, when you switch cards in a Container with a CardLayout, the Container will fire a cardswitch event once it’s done. We can hook into these events and destroy Components that are not visible anymore because of these transitions.

Let’s look at a simple example. Our goal is to have a List that slides to a details panel whenever you tap on an item. Once we get to the details panel, we want to destroy the List. Then when we go back to the List, we want to destroy the details panel. This way, we ensure the minimum required markup in the DOM at any given time.

Example

Here is an example of the code for the List:

var list = {
             xtype: 'list',
             title: ‘Contacts’,
             listeners: {
                     itemtap: function(item) {
                                     details.html = item.details;
                                     panel.setCard(details);
                     }
             }
             ... list & store configuration ...
        };

Note the use of xtype. Here, we are not creating an instance of our list, simply a JSON object representing the object. This way we can destroy and recreate our list easily.

We do the same for the details panel, except in this case, we will put a Back button inside the panels top toolbar which will cause the container to show the list again when pressed.

var details = {
             xtype: 'panel',
             dockedItems: {
                     title: ‘Details’,
                     dock: ‘top’,
                     items: {
                                     text: ‘Back’,
                                     ui: ‘back’,
                                     handler: function() {
                                                 panel.setCard(list);
                                 }
                     }
             }
             ... component configuration ...
        };

Now, we get to the interesting part. Let’s create the following Panel which will contain our child components.

var panel = new Ext.Panel({
             fullscreen: true,
             layout: 'card',
             items: [list]
        });

As you can see, we have created a fullscreen Panel with a layout of card that contains our list by default. We haven’t put in the details panel yet. Instead, we will only insert the details panel when you tap an item.

Now, it’s time to set up a listener to the cardswitch event. This is where we actually ensure that the card we just came from is being destroyed.

panel.on(‘cardswitch’, function(newCard, oldCard) {
             if (oldCard) {
                     this.remove(oldCard, true);                    
             }
        }, panel);

As you can see, we are removing the old card from the container. By passing true to the second argument of the remove function, the container will call the destroy method on the card—also removing all of the events bound within that object as well as the actual DOM created.

This same concept applies to hiding a modal window or popup. In fact, you can apply this concept to almost any visual state change of your app. Of course, you want to find a balance between reducing your app’s memory usage and rendering heavy components again and again. In some cases, the benefit of not having a long rendered List in memory is offset by having to render a very long list again when you switch back to it.

So far, we have looked at event delegation and DOM cleaning as ways to reduce your applications memory usage. In a future article, we will look at things you can do to improve the performance of your animations. Till then, delegate and keep your DOM clean!