Things to take care while developing a phonegap app

Before my first phonegap app I worked on many web projects, and experience with my first phonegap app was completely different. I learned much about perceive performance and areas where to see for maximum performance. I also learned about content management in an app to reduce the load.

Mobiles have limited resources and you have to create one page app to have smooth transition between views, in other word you have to fit an elephant on a small box.

This article will be on my experience and what need to be taken care while developing a phonegap app. Many of this also make sense for any web project. Before starting about my experience and what I noted on it, I want to give a small overview what phonegap is and how phonegap app works.

Phonegap is powered by apache cordova which exposes device level API to JavaScript. Cordova uses web view to render views. So you are creating your project in HTML, CSS and JS which runs on a web view and communicating with device APIS using cordova as a bridge, empowering you to develop cross platform apps. But here the problem come, as you are using web view to render HTML, it gets a very limited resources making your app running much slower than a native application. Unfortunately web view is slower even from a mobile browser, so things which run good on a mobile browser, does not work same on  web view.  However web view is becoming more powerful on latest devices as mobile specifications are increasing. Hope in some day you will not be able to distinguish between a phonegap app and a native app.

So let’s see what I learned from my first app.

Figuring out can it be done on phone gap

Figuring out whether your app can be done in phonegap or not is very important part, so you must not stuck on middle or end up delivering an app which is not as usable as it should be.  Apps having small code base , light UI, less data manipulation, less no of list item (less html) are optimal for phonegap apps. App having heavy data manipulation and UIs, using too much resources are not advised to be built on phonegap. My app was in middle of both, it was not optimal but was doable, but it needed a lot of optimizations to have smooth experience. This leaded me to write about next points.

Do you really need a framework or a plugin?

When I started my app, I choose jQuery mobile, learned its APIs and started building my app. Soon after implementing first experimental page, I figured out that there were lot of overwriting of CSS and JS to fulfill my requirements. I checked about how many APIs I will be using of jQuery mobile on my app, I got it to be too less and page transition and many other features are not matching my requirement. I also saw jQuery mobile does a lot of layout transformation creating more elements, and some of CSS were not optimal for phonegap app. However it’s not same for all situation, for light weight app things can be done faster on jQuery mobile. It’s good for small apps and obviously for mobile websites, but for performance killing app it’s not optimal.

Same with some plugins or libraries, if you are adding a plugin/library in which you are using its small sets of feature, than better you should not add it at all.

I found it’s better to create things from scratch, having own codebase and use micro plugins which just do what we want.

Understanding reflow and repaint

If you are developing a phonegap app, you must know what reflow and repaint is, what causes it and how to minimize it.  Reflow (Relayouting elements) and repaint (Redrawing pixels) are one of the biggest factor of slowing down the performance, yet they are important for a browser to properly render the view.

Reflow is caused when there is change in any dimension or position of an element or any DOM manipulation, and repaint  is caused when there is any change in visual styles. Reflow also cause repaint, and reflow of one element can cause reflow to many element. This all are done to maintain a proper layout and style. This two are very heavy work taking much system resources. Reflow and repaint are un-avoidable but can be minimized. Reflow is more costly than repaint (There are also nothing more to do about repaint), but minimizing reflow can lead to more fluid app.

As I told a reflow to one element can cause reflow to number of elements (Aka, all its descendent, siblings and ancestor element), a proper html structuring and proper DOM manipulation can help a lot. For example making two point of element unrelated to each other, having less number of html element, doing DOM manipulation at once, so for number of changes there will be one reflow . Doing manipulation on offline nodes and attaching them to DOM on last.

Some useful resources to know more about minimizing reflow or repaint.

http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/

http://dev.opera.com/articles/view/efficient-javascript/?page=3#reflow

http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/

Say goodbye to shadow and gradients

Shadow and gradients require more CPU to be rendered and they are very costly on performance during repaint. So having a Flat UI is much faster than having shadow and gradient UI. Gradients and shadow are ok to be used on elements where there is not much reflow or repaint or in few places like button or headers/footers, but having them on large list item is like killing your app.

CSS3 Animations and transition instead of jQuery animation or any other JS animation library

CSS animations are much faster than jQuery animation or any other JS animation library, as JS animation libraries use setInterval or setTimeout to create steps of animation which causes more number of reflow/repaint. On other hand CSS animations/transitions are handled by browser engine which are faster than JS and also causes less number of reflows.

It’s also worth to note that having transition on translate properties is much faster than transition on position properties.  

Get benefited from hardware acceleration

You also can use hardware acceleration for some elements of your app, means any style change will be done by GPU and not CPU which provide smoother effect. Simplest way to do this is to add css property “transform : translate3d(0,0,0)” on element which you want to be hardware accelerated.

This small piece of CSS can have a big difference in smoothing any transition or animation. But be gentle on making element hardware accelerated, adding too much element in GPU can crash your app.

Native scrolls are not good as simulated scroll

It’s very unfortunate but true that native scroll in web views are jerky and slower than simulated scrolls. And it’s also good to know that simulated scrolls have more control over scroll than a native scroll. There are many plugin available for simulated scroll, but from my point of view IScroll is best of them, and I am too using that. Most of scroll plugin, including IScroll uses transform (translate) property of CSS to simulate scroll.

Whatever scroll plugin you are using, I will advise to read there documentation completely and create some experiments to check how much they are fitting to your project.

Content Management (Have minimal content at a time)

This is biggest factor which can make your app more slickly and smooth.

As for html contents I told reflow of an element can cause multiple reflow of other elements, so as the number of element increases in DOM, there is that much chance of reflows.

Basic fundament is to have a limited content at a given instance of time. So keep only those content (html) which is visible at that time and few more to maintain perceive performance, and delete all other which are not visible.

Same with cleaning JS objects or variables which are no longer required.

This part requires a huge effort of thinking process, so you can have non flickering UI while keeping least content at a time.

So let’s discuss about the common places where content management concept should be applied.

Page management :

As most of phonegap app are made single page application and mine too, you have to add all pages in single page. But coding all html on single page may result lot of content on initial (If you are not deleting after app start, unseen content will be always there.)

So first I thought to have main (index.html) file minimal, and adding content through JavaScript (Even adding pages from JavaScript.) This was solving problem of having large number of DOM element by having html element as a string in JavaScript which consume much less memory than adding it on DOM.

But maintaining pages html and edit them in a string is hectic. So best solution was to create a separate html files for each page and load them through Ajax when it is required.

Now things were not on DOM element as well as JS variable. This was more optimal.

It’s also worth to create a Page class and creating instance for all pages which contain methods, to load page content through Ajax, add it on DOM, remove it from DOM, show page, hide page, a page specific selectors caching factory and event binding scheme.

Be careful whenever you remove elements from DOM and re add it you have to rebind events and refresh the cached selectors. And also do loading content through Ajax before showing page, as your app should not look blank at any point.

  1. Apply pagination : It make a lot of sense to apply pagination in pages where it can be applied. So asking users to load more content if they require or adding page numbers, can reduce the number of elements you are loading on your page.
  2. Handling a long list on scrolling : In my project I also faced a problem of having a long list of elements. I was having a lot of gesture and content on one list item. This was making my app slower and jerky. I was also not able to add a pagination concept because I need to keep everything on one scroll, at the same time I wanted less number of DOM element.So solution which worked for me is by keeping a fixed number of element on the start and during the scroll adding elements on last and removing from top while adding exact amount of padding equaling to height of elements removed from top to maintain proper scroll position, and doing same while scrolling from bottom to top, removing from bottom and adding on top.This process requires an accurate handling of scroll movement and proper scroll positions, points where to add element and remove element to have a smooth scroll experience while controlling list manipulation. So do lot of experiments and testing to do this, otherwise you can result worse feel on scroll.
    Update :
    The other solution which worked more better for me was to keep all list item as position absolute and translate them in y direction such that every item comes one by one. With this way you don’t have to worry about maintaining padding on parent, and it also causes less reflow which makes scrolling more performant. This works only when you can calculate or know the height of a list item.
    Here is a small plugin to handle long list scroll with the second approach https://github.com/s-yadav/LongListScroller
  3. Perceived Performance : Perceived performance is always been the key part of optimization. It’s a practice of making user feel your app is slicker even not doing much on actual performance optimization, just by changing the way of loading and showing the content. While creating a mobile app we can follow few things to have great user experience.
  4. Don’t make user to wait : User always want an immediate response for his action, either page change or any button press. So let them have a quick response on their action.Show him some loading icons if it takes time to get content. Or show only few data after page change and then update the content before he performs any other action.
  5. Manipulate content during animation/transition : You can get greatly benefited by animation/transition, if you are using CSS transitions. As transitions are asynchronous job of browser you can perform other task as well during transitions, and that way you get more time to manipulate content, even on most of time your content will be ready before transitions or animation is finished.
  6. Pre load content : Pre loading of some content which are repeatedly used or content which are going to come on next page can be preloaded before they are needed. For most of content except repeatedly used element (loading icon, close icon, etc.), it’s better to store them on JavaScript variables instead of DOM to have less content on DOM.If you have to make Ajax call to load next page content load them before and store in JS variables as string and on click of page navigation link add them on DOM. This reduces response time and make your app feel smoother.
  7. Post load content : An opposite concept of pre loading is post loading and both should be applied on right places. So have a quick response on user action show few content of what he want, and as soon you got some CPU free , load the rest of content.Let’s see an example of this.Suppose you have a 100 list item in a page, so when a user action happened to load that page, add only 10 or 15 list item which are visible (this will take less time of rendering), and as soon you reach the page load the rest of list items, before user performs a scroll.Post load concept can be followed for any content which are not visible on the start.So if things are not visible, if they are going to be visible on some user action, then let’s load them later and load the content which user sees the first.

300ms delay on click

Mobile browser or webview have 300 ms delay after tap to consider it as click event. This delay comes on all click-based interactions such as links and form controls and any element in which click event is assigned. This can make feel your app unresponsive and for no reason.

I liked a light weight plugin “FastClick” to solve this problem. It’s very easy to initialize on body and plugin will take care for click events of all element.

There are also many touch based event (tap, swipe, double tap) simulation plugin which used different combination of touchstart, touchmove and touchend event. You can use any of them according to your requirement.

You can also simply use touchend event instead of click event which will not cause delay, but sometime they are fired unintentionally especially during scrolling on page.

setTimeout with 0ms

setTimeout, setInterval are asynchronous methods of browser. Async methods are register and are watched asynchronously but callback registered with async methods run synchronously.

It’s very important to understand how code execution works in browser, let’s see an example for this.

 

Now in following steps our code execution will finish.

  1. Create an array and store on htmlStr, make a loop of 1000 times and push list item html string in array.
  2. Join array to form string and add it to listHolder element (add on DOM).
  3. Register a reflow/ repaint for listHolder element.
  4. Register a setTimeout of 0 ms and push settimeout callback in async queue after 0 second.
  5. Create a string and substring
  6. Register a second settimeout of 0 ms and push callback in async queue after 0 second.
  7. Reflow /repaint is done
  8. First timeout callback will be executed
  9. After alert is closed, second time out will be executed and substring is alerted.

Here we see there is hidden work of reflow/repaint which are registered at the point of DOM or style manipulation and are executed when processor is free and also they block the thread while they are on process. Reflow/repaint can also be triggered in middle of execution by asking for any style property which need to be calculated.

Note Time taken in reflow/repaint and there execution point may differ browser to browser , but the concepts are same.

Same with the setTimeout method they are not been alerted at the same line they registered (Which it seems to be as they have timeout of 0 ms). Instead, after 0ms, as callback function is a synchronous they are pushed on asynchronous queue which is executed after processor is done with other statements.

Now this hack of adding setTimeout with 0 ms helps a lot in executing some code after all reflow/repaints are done, which make sense on mobile browser, especially on web views where reflow/repaint takes much time.

There are lot of scenarios where this hack should be used but let’s give two simple example.

  1. In a phone gap there is method to hide splash screen after your html element is ready. But if you call that function just after adding html and if number of element in added html is large, for a fraction of second you will see white screen or whatever is on html background and then you will see content. This is again because after an html is added there will be reflow/repaint which will take some time to be completed. So hide splash screen method can be kept inside a setTimeout with 0 ms, so that splash screen will be hidden after all reflow/repaint are done (When content is actually and properly visible).
  2. Secondly, suppose you want to animate a dynamic added element with CSS transition, just after they are added than following statement will not work.

    Now there will be no transition on newDiv even there is transition property defined on top in animate class. The reason is as html, reflow/repaint is registered after adding content, but not executed at that point and after applying CSS a new reflow/repaint is registered for newDiv. So when the reflow/repaint of newDiv is finished the top position is already been changed, having no transition effect, as transition work on element after its initial reflow.

    Now we can make that code work by simply adding setTimeout.

    In this case CSS of .newDiv is changed after the initial reflow/repaint is done. So transition will work as intended.

Writing build scripts

In a phonegap app as available resources are less, concatenating and minifying CSS and JS can make a difference. But doing this manually, all time you make a change in your JS or CSS file is painful.

It’s also good if you want a change to be copied on all platform specific folders.

(Not to be confused with phonegap build. As they do copy from www folder to patform specific folder but they also build platform specific phonegap code, so if you have done any change in any one of platform manually they will be overwritten. )

So it’s better to write a build script to this task automatically on code change.

There are many tool available online for writing build script which you can use.

I too have written a boiler plate for writing build script with node.js which contains ready to go methods to do such task. You can download it from http://github.com/s-yadav/node-website-build-script .

Strategy of optimizing

Optimizing a wrong part of your code can waste your lot of time. So it’s good to optimize on the part first which affects most. Obviously we should take care of optimization along with coding, to reduce effort of optimizing later after finishing project.  So I made a following flow to optimize my app.

  1. Optimize for perceive performance.
  2. Optimize to minimize reflow and repaint
  3. Moduling code, removing repetitive code
  4. HTML optimization (Having a better DOM structure)
  5. JS optimization (logics)
  6. CSS optimiziation

Specific to phonegap app, some CSS optimation (like hardware acceleration with CSS) and html optimization can make a lot of difference in performance.

You may also like to check this.

http://www.tricedesigns.com/2013/03/11/performance-ux-considerations-for-successful-phonegap-apps/

http://coenraets.org/blog/2013/05/top-10-performance-techniques-for-phonegap-applications/

10 thoughts on “Things to take care while developing a phonegap app

  1. Awesome post about optimizing phonegap apps. Keeping this as a refrence.

  2. I usually use Phonegap because it’s simple to use and you can quickly move in your .html, .css and .js information. JQuery Mobile is a scripting terminology and that doesn’t create an app, just a web site. Phonegap uses your information to create an app, like an installable apk. You actually create it seem so simple with your presentation .thanks for sharing…

  3. Learnt a lot. Thank You..!

  4. Very useful information, thank you

  5. very very good work. thank you

  6. Thank you,Great information

  7. Gollapalli John Peter

    Thanks, Very Useful Information

  8. thanks dude , it was so useful for me.
    you can also use new frameworks link phonemon and http://onsen.io/ .

  9. Might be a bit cheeky, but would it be possible you fiddle your “long list scrolling” solution? It’s been giving me a nightmare for past couple of days in androids < 4.4…

    I'm having a list of 500 items, which flickers tremendously when scrolling…I temporarily ended up with writing a plugin that sets render mode to software on those browsers, but as scrolling now seems jerky, it would be nice to have HW acceleration back in also older browsers supporting it…..I'm using iScroll5 to handle the scrolling

    Any help would be greatly appreciated

    • I know, its a late reply, but as many people were asking, I uploaded a small Long list scroller plugin ( https://github.com/s-yadav/LongListScroller ) to keep limited list item in the dom. I thought you may find it useful.
      You can play around with plugin options to fit your requirement.

      PS : You need to disable hardware acceleration below android 4.4 as android webview has many glitches with hardware acceleration on.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">