theboywhocriedWoolf | Tal Woolf

Appcelerator

0

Friend or Foe

When it comes to creating mobile applications there is still no argument that native is without a doubt the best approach. But if you are trying to recreate the Great Wall of China, using nothing but a bucket and spade, Appcelerator could be your light at the end of the sand filled tunnel.

Appcelerator provides an ‘as close as it gets to native’ application creation using the web languages we all know and love, on top of being bundled with pre built tools and components which really help you create that native application look and feel.

It achieves this by compiling your JavaScript creating native code bindings, which are interpreted at runtime using JavaScriptCore on iOS and Mozilla Rhino on Android and Blackberry so although it’s not completely native, at this point in time it’s as close as you are going to get.

Do I know You?

If you are a familiar with JavaScript then the transition to Appcelerator is a relatively easy one. Adopting the ComonJS module specification makes it easier to structure your code into modules, simulating more of a class-based structure, which let’s face it is always a good thing.

However, don’t be fooled, it is all too easy to get carried away structuring your application in the way you would any other JavaScript project to soon find that your application starts running like it’s been smoking forty packs a day for the past twenty years, struggling to keep up with even the simplest tasks.

Therefore before you start coding away at your application, it is important to get a better understanding of how to structure your code to try and avoid any inconsistences and hidden performance pitfalls.

There are lots of resources online which although many are outdated, will still provide you with the basic knowledge and approach, I also recommend reading ‘The Appcelerator’s Best Practices Guide’, or better still have a look at Appcelerator’s ‘Best Practices and Recommendations’ where you can find sample applications to download and play around with yourself.

Stop Copying Me

As with most programming language best practices and design patterns, it’s important to modulate your code wherever possible, creating reusable factories and components. This is especially true within Appcelerator to stop you from becoming repetitive and give you more control over your application. You can get a helping hand by looking into ‘Appcelerators Building Reusable Factories’.

To prevent you from flooding the global scope, while also increasing control and load management of your modules it is more advisable to append all of your reusable modules to one global object. This can be any object of your choice or simply append them to the Ti.App module object which is a top-level module and is globally available throughout your application.

To see how to create modules take a look at the CommonJS modules in Titanium.

UI Factories

With modularity in mind, instead of using Ti.UI throughout your application to instantiate custom UI elements create a UI factory module that can be used to instantiate new UI components for reuse throughout your application.


var UIFactory = (function()
{
      var self = {}; // clazz

      self.getView = function(props)
      {
          var view =  Ti.UI.createView(
          {
                width 	: Ti.UI.FILL,
                height	: Ti.UI.FILL,
                touchEnabled	: false,
                enabled       : false
           });

          if( props !== undefined ) view.applyProperties( props );
          return view;
      }

       // add more custom views...

     return self;
})();

// Then append to a global object
var global.ui = UIFactory;

// Alternatively you can append it to the Ti.App module
Ti.App.ui = UIFactory

// USE by
var newView     = Ti.App.ui.getView( {
                prop : value
                prop : value
          })

Singletons

CommonJS modules are themselves singletons and unless you instantiate them using the “new” keyword then they will act as such.

So depending on your application and the way you decide to load in your modules you should be able to utilize Singleton functionality with ease, just make sure that you instantiate these objects in the right way depending on your loading method using ‘require’ or “Ti.include() and above all make sure you done overload the global scope.

Get out of my Global Scope

If you require one off calculations or functionality such as installing a database, adding a view to the display list or even iterating through a loop to return a result you should probably keep this functionality out of the global scope. The best way to do this is using self-instantiating functions which means that all temporary variables and methods used will remain within the scope of the function, only being removed once the function has completed its calculations helping to manage memory and prevent memory leaks from retained objects and variables.

For a more in depth explanation have a look at ‘Coding Strategies‘.

Nullification if you Please

Nullifying your variables and objects is even more important within Appcelerator without it you could find yourself leaking memory all over the place so much so even garbage collection won’t be able to help you.

This is an intrinsic process and can be a little frustrating at first similar to the days programming in iOS before ARC was introduced, but if anything, thinking about garbage collection will in turn make you a better and more careful developer. Plus there are a few handy techniques that you can use to help you:

- When using local variables nullify them after their use.
- Create a module to deal with all of your nullification requirements, passing all your objects through to it when you want to dispose of them. This can help you correctly remove children from the display list before nullifying them, as simple removing from the display list won’t remove them from memory.
- Create a dispose method within each object that takes care of all its nullification before removing itself.


// nullify after use
var view = Ti.App.ui.getView({});
applicationWindow.add( view );
view = null;

// create module to deal with nullification
var NullModule = (function()
{
     var self = {};

      // dispose view
     self.disposeView( view )
     {
         var i = view.children.length
         while( --i > -1 )
         {
            view.remove( view.children[ i ] );
            view.children[ i ] = null;
         }
         view.children = null;
         view = null;
     }

     // further methods, such as dispose children from ScrollableView etc.

     return self;
})();

// adding a dispose method is self explanitory

But always make sure you debug your application watching your system traces, as Appcelerator will run regardless of errors trying to add null children to the display list.

Contextualise This

Although JavaScript is a single threaded language and runs within a single scope it is possible within Appcelerator to invoke several JavaScript processes each with their individual scope known as “Execution Contexts”.

It is not recommended to use several contexts throughout your application and unlike multithreading in iOS it is not particularly useful to try and run computational tasks in separate contexts to try and free up some processing power for your main context.

However, if you separate and run your main application modules or views in separate window contexts, running and closing them respectively when they are no longer needed this dramatically helps speed up your application.

Generally any view or functionality that is independent of the rest of the application could benefit from being within its own window context depending on its use.

However for one context to communicate with another you must use events. This also poses a problem when reading and writing locally.

So be mindful, especially if you are using separate contexts to read and write local files, as one context can often have issues trying to read a file or database created or being used by a different context.

A good explanation although a little outdated can be found under ‘Understanding execution contexts’ or ‘JS Environment’ by Kevin Whinnery.

WebViews to the Rescue

Depending on the requirements of your application, WebViews on Android can help to massively increase your applications performance; this could be the same on iOS although I have not tested this yet.

For some reason, animating views on Android seems to take an incredible amount of processing power causing the application to jitter. For a while I tried to solve this by implementing a custom frame independent animation method, using a timer and calculating the delta time between frames without any luck.

Don’t get me wrong they come with their own set of inconsistencies and problems, which I will go into in a moment, but if you are trying to create an application with animation, sliding views or specialized interaction which goes outside the realm of the ScrollView or ScrollableView, then WebViews can be your light at the end of the tunnel.

Inconsistent you Say?

When using WebViews you have several options for setting their content:

    – Data: Accepts blob file
    – URL: Accepts local or remote URL to a HTML file
    – HTML: Accept HTML Content as a string

In my case I wanted to use a single local HTML file, load it into my application view and then change its content based on the views required information.

So, my logical approach was to pass in the URL of my local HTML file to each view, run a series of evalJS functions passing parameters to JavaScript methods within the page and then change the pages content on the fly.

If you are not sure what evalJS isit’s a way to run JavaScript expressions inside the context of the WebView.

// all arguments passed have to be in string format

// get element on the page
 webview.evalJS("document.getElementById('gas')");

// run a method
webview.evalJS("methodName()");

// to pass values using variables, the variables themselves must be wrapped in quotations
webview.evalJS("methodName('"+ variableOne + "')");

The problem with this is that the JavaScript on the page can only be run once the page is loaded and if you are only adding views as and when they are needed your JavaScript methods can often cause your application to freeze. I came to discover this happens because the page is being re-shaped and often, in plain sight, displaying the original content and then magically changing it.

Your obvious approach would be to preload your views so you would have them already rendered and ready to go when called upon.

Fixed, or so you would think… as it turns out, Android has and has had for a while an issue with rendering webviews if you are using Hardware Acceleration within your application (which if you want your animations to be running  more smoothly, you should be).

To turn hardware acceleration simple add this line into your tiapp.xml.


<android xmlns:android="http://schemas.android.com/apk/res/android">
       <tool-api-level>11</tool-api-level>
       <manifest>
             <application android:hardwareAccelerated="true"/>
       </manifest>
</android>

The problem is that the WebView only seems to start rendering once it is added to the display list and not only that it needs to have its visibility and its parents visibility set to true, while also being in the applications visible bounds. So in many instances this means your WebView will flash white before showing its content.

After scouring the internet, posting questions to the Appcelerator support team (which are very responsive I might add), reading many articles and trying to find solutions to this problem it turns out that at this particular moment there aren’t any, not for Appcelerator anyway.

The only way around this and it may not be the best solution, but it worked for me, is to create a render factory module. Basically create module with a view or window that is behind all your other views and can even have a height and width of ten pixels, as long as it’s in the view bounds with its visibility set to true.

Each time you pre-create your next and/or previous webviews pass them into that module which will then in turn add them to its display list and kick start their rendering process. When you require your webview; request it from the factory. This will remove it from its display list pre rendered and ready to go, seemingly taking care of the white flash issue.


var factory = ( function()
{
   var self = {}; // class

   self.init = function( parent )
   {
      // add to parent, make sure z index is set to stop from being visible
   }

   self.addViews = function( views )
   {
      // loop through views and add
   }

   self.getViews = function()
   {
       self.remove( view / views );
       return view/ views;
   }

   // could implement a add method passing a view id and a get by ID method

   return self;
})();

Obviously, it is also best to make sure that the WebViews loaded event has also fired before you receive it back. So if you can build in a clause which if the view has not yet loaded, starts a timer to check if it’s available and only feeds it back to your main view when it’s good and ready.

Finally, to speed up the process and not have to run any JavaScript methods within a page you can simply load in your HTML, as a String from a text file, and replace the content within your HTML tags before loading it into your WebView, using the HTML method.

If you are also planning on using local JavaScript files and or CSS files with this method, you must make sure to inject their location within the application into the page, as unlike using a local HTML page, you cannot use relative paths.

You may also sometimes notice scrollbars appearing on your WebViews, even though they shouldn’t, this issue was fixed within Appcelerator but you need to add this to your tiapp.xml:


<property name="ti.ui.defaultunit" type="string">system</property>

Extra Nibbles

If you are developing for Android and find that when you install your application on the device, it always requires the application to re-launch before starting, you need to add this to your tiapp.xml:


<property name="ti.android.bug2373.finishfalseroot" type="bool">
     true
</property>

So, I guess in conclusion I would recommend Appcelerator if you are short on time and/or knowledge of native implementations because it is quick to pick up and has many tools and components to help you with standard views and functionality…its performance isn’t half bad also.

I have created a few modules that may help you in your development, so feel free to Spoon me on GitHub.

Perhaps also pick up a hobby such as juggling, to fill your time in between compilations….

Leave a Reply

(* Required)