Add project as library – Titanium module (Android)

Native Android application can include other projects as library, when they need that particular SDK library functionalities – using Eclipse, right click project > Properties > Android > Library. However for Titanium module, there’s no option to add other projects as library. Instead, we need to include the whole project itself into the module project directory.

For example, I’m creating GooglePlayServices module, so I need to copy files from ANDROID_SDK_DIR/extras/google/google_play_services/libproject/google-play-services_lib/ into the module folder

export MODULE_DIR=~/Workspace/ti.googleplayservices/
cd $ANDROID_SDK_DIR
cp -r libs/*.jar $MODULE_DIR/lib
cp -r res/ $MODULE_DIR/platform/android/
cp -r src/ $MODULE_DIR/src/

Most of the time, the library that being included will be missing R.java and BuildConfig.java file. Depending on the library itself, create those files manually. For this GooglePlayServices module, the generated resource file (R.java) is located at com.google.android.gms namespace:

touch $MODULE_DIR/src/com/google/android/gms/R.java

(for Facebook SDK that I created sometime ago, it’s at com.facebook.android)

Now, again depending on the library we’re including, the content of R.java can be found either from the source code (like Facebook SDK) or from the documentation (GooglePlayServices).

Originally, R.java is generated by Android build tool when building APK file for a project, but since we’re building a Titanium module, R.java cannot be generated, since it’s value might clash with the actual project that use this module. Values inside R.java are generated from the XML resources (such as strings.xml, values.xml, layout.xml), or graphic files (icons / images files, also known as drawables).

The difference between this file and the generated one, is that we need to initialize it to populate its values. By using TiRHelper, we will get and assign all the values at runtime.

package com.google.android.gms;

import org.appcelerator.titanium.util.TiRHelper;
import org.appcelerator.titanium.util.TiRHelper.ResourceNotFoundException;

public class R {

    public static class attr {
        public static int adSize;
        public static int adUnitId;
        public static int allowShortcuts;
        // ... more ...
    }

    public static class color {
        // ...
    }

    public static class drawable {
        // ...
    }

    public static class id {
        // ...
    }

    public static class integer {
        // ...
    }

    public static class string {
        // ...
    }

    public static class styleable {
        // ...
        public static final int[] AdsAttrs = {
            styleable.AdsAttrs_adSize,
            styleable.AdsAttrs_adSizes,
            styleable.AdsAttrs_adUnitId,
        };
        // ... more ...
    }

    public static void initialize() {
        R.attr.adSize = getResource("attr.adSize");
        R.attr.adUnitId = getResource("attr.adUnitId");
        R.attr.allowShortcuts = getResource("attr.allowShortcuts");
        // ... more ...
    }

    private static int getResource(String path) {
        int id = 0;
        try {
            id = TiRHelper.getResource(path);
        } catch (ResourceNotFoundException e) {}
        return id;
    }
}

Then, in the main module class, don’t forget to call initialize() method on app creation.

@Kroll.onAppCreate
public static void onAppCreate(TiApplication app) {
    R.initialize();
}

Use view from custom module inside Titanium ListViewItem

Most example I found on how to create view inside ListViewItem are using Titanium views itself (those from Ti.UI namespace). This post shows how to use views from other modules. For example, I’m using canvas view module, TiAndroidCanvas (Android) and ti.canvas (iOS)

Updated:

In order for ListView to use the custom module, listview.js need to be able to access the JS variable pointing to the module, and invoke the create* method to create the view instance. So, instead of using try-and-error method as shown previously, just assign your require()-ed module to global scope

Android example:

global.CanvasModule = require('com.wwl.canvas');

// template
{
    type: 'CanvasModule.CanvasView'
}

(therefore, listview.js will invoke CanvasModule.createCanvasView() to create the view instance)

iOS example:

global.CanvasModule = require('ti.canvas');

// template
{
    type: 'CanvasModule.View'
}

(therefore, listview.js will invoke CanvasModule.createView() to create the view instance)

Android

Include the module into global variable, then in ListItemTemplate, assign using the view’s class name (in Java source code, the class that inherits TiViewProxy, without -Proxy suffix)

var Canvas = require('com.wwl.canvas');

// in template
{
    type: 'Canvas.CanvasView',
    properties: {},
    events: {}
}

iOS

No need to include the module, but in ListItemTemplate, assign using the actual view proxy class name in Objective-C code.

// in template
{
    type: 'TiCanvasView',
    properties: {},
    events: {}
}

Titanium app components interaction using events and callbacks

Events

Events are used to broadcast an action happened to zero or many receipients.

Example, in a list of items, when user click on ‘Load more’ button at the bottom of the list, at least 2 actions need to be executed simultaneously – show the loading indicator and start fetching more data from web service.

var btn = Ti.UI.createButton({ title: 'Load more' });
btn.addEventListener('click', function() {
    webservice.getMoreData();
});
btn.addEventListener('click', function() {
    loadingIndicator.show();
});

Another example is, when the loading data process is done, an event is being broadcasted.

webservice.addEventListener('data_received', function(data) {
    if (win) {
        renderData(data);
    }
});

Here, if the current window is still opened, at least one receipient will respond to that event, or else there’s no receipient at all.

Callbacks

Callbacks are used as an immediate respond to be called right after a block of code has done executing. Callbacks can only be attached to only one function call – only have one receipient that respond to it. Callbacks are suitable to use on a function call that will return result asynchronously, but return response differently everytime.

Example, when calling a function to retrieve ID3 tag info from an MP3 file, a callback is passed when the retrieve process is done.

var ID3 = require('module.id3tag');

ID3.getInfo({
	file: Ti.Filesystem.getFile('song.mp3'),
	success: function(e) {
		Ti.API.info('Song artist: ' + e.artist);
	}
});

Object oriented Javascript with CommonJS in Titanium app

Class definition

// class definition + commonjs module
function ClassName() {
    // code...
}
module.exports = ClassName;

Use normal javascript function as class definition. Follow certain class / function naming convention to make sure you are not confused between a class or a function. For example, class name use Pascal case (ClassName), while function name use camel case (isFunctionName).

Public / private methods

By utilising the scope of function or variable definition, we can make that function/variable to be public or private

function ClassName() {

	// public method
	this.getData = function() {}
	
	// private method
	function processData() {}

}

After instantiating ClassName, we can invoke public method on the object. Private method will never be accessible outside of the class scope

var cls = new ClassName();
cls.getData();

Public / private properties / variables

function ClassName(args) { // `args` will be private variable

	// private properties/variables
	var pageNum = 1;
	
	// public properties
	this.version = 1.0;

	// getter
	this.getPageNum = function() {
		return pageNum;
	};
	
	// setter
	this.setPageNum = function(num) {
		pageNum = num;
	};
	
}

Similar to public method, only public properties are accessible from the object created. Developer can use getter/setter method to access private properties. Getter/setter method is useful if you want to keep private variables from being modified outside of the class.

It’s a good practice to use getter/setter on object properties, because we can control who can modify the object properties and when it is modified by external component, we can customize the behavior.

// for example, here is method set the page number of an object.
// in this setter method, we can customize the behavior in case 
// the external component provide invalid input
this.setPageNum = function(num) {
	if (num < 1) {
		num = 1;
	}
	if (num > maxNum) {
		num = maxNum;
	}
	pageNum = num;
}

Static method/properties

ClassName.getName = function() {};
ClassName.appName = 'test';

// static properties can also used as constant
ClassName.APP_ID = 'xxx';

Inheritance

There are no direct way to achieve class inheritance similar to what Java, Python or other languages that have true OOP feature. In Javascript however, we can extend an object functionality by defining it in another class.

function NewClassName() {

	var self = new ClassName();
	
	// extend object with new method
	self.processSomething = function() {};
	
	return self;

}

Another way to customize a class is that class must provide some kind of abstraction. So that when instantiating the class, we can pass some arguments to it to modify its behavior (kind of polymorphism).

function AnotherClassName() {
	
	var self = new ClassName({
		id: 1,
		name: 'abc',
		onClick: onClick
	});
	
	function onClick() {
		// code...
	}
	
	self.doSomething = function() {};

	return self;
	
}

// using the child class, we still can invoke methods from parent class
var acn = new AnotherClassName();
acn.getData();
acn.doSomething();

Efficient code

From my experience, an efficient code is code that have these characteristics:

  • it works
  • use optimum resource
  • manageable

Note: example codes are in Javascript, specifically Titanium mobile.

An efficient code must be code that can be run. There’s no point of evaluating a code that doesn’t run at all. Secondly, it must solve the problem it’s required to.

Example, a function must return letter ‘S’ for person with weight 50kg and below, ‘M’ for 51-70kg and ‘L’ for 71kg and above. So, the code must comply to this requirement

function getSizeFromWeight(weight) {
  if (weight <=50) {
    return 'S';
  }
  else if (weight <= 70) {
    return 'M';
  }
  return 'L';
}

Note: don’t bother to assign the result to another variable, just return it immediately.

An efficient code that use optimum resources, means the code only create necessary variables and use external resource such as filesystem, network connection, database or plugins only when needed and release those resources when done.

For example, iterating a list of files and getting each of the files’ modification timestamp, for each files that are modified a minute ago will need to be deleted. Some newbie programmer will collect a list of files that need to be deleted and then delete them, one by one. There’s nothing wrong with this method, except the code need to iterate twice in order to delete the expired files, which is inefficient.

var now = new Date().getTime();
var files = []; // assume this contains Ti.Filesystem.File objects
var i = files.length;
while (i--) {
  var f = files[i];
  if (f.modifiedTimestamp + 60000 < now) {
    f.deleteFile();
  }
}

Notes: Some loop statement (e.g while loop) is generally faster that other (for, foreach, do while).

Lazy loading is one of the technique that explains how to use optimum resource. Example, in a Titanium app, when a window opened, we only include those modules that required in order to open the window. If your app need to play audio, only load the audio player module when user invoke the functionality (via play button click etc.)

// open a window
var win = Ti.UI.createWindow();
var TopBar = require('ui/TopBar');
var ContentGrid = require('ui/ContentGrid');
win.add(new TopBar());
win.add(new ContentGrid());
win.open();

// play an audio, when click the play button
playBtn.addEventListener('click', function() {
  var Player = require('lib/Player');
  Player.start(this.audioUrl); // assume playBtn has this property
});

Note: During opening a window, only include UI components required in order to build the app window. And only when the play button is clicked then include the audio player module.

Code manageability means when you need to fix bug, add new feature or rewrite the code to accommodate new infrastructure, the existing code require little or zero adjustment. These small adjustment won’t break the current system.

Example, also in Titanium app, you have a feature to check for a new version of your app from the webserver. In initial release, the app only need to know the version number. Then in subsequent release, you want to add download link, thumbnail image etc. Current code shouldn’t have to be adjusted too much, till it break the calling component.

// initial release
function notifyNewUpdate(p) {
  Ti.UI.createAlertDialog({
    message: 'Version ' + p.version + ' is ready to be downloaded'
  }).show();
}

// subsequent release
function notifyNewUpdate(p) {
  var dialog = Ti.UI.createAlertDialog({
    message: 'Version ' + p.version + ' is ready to be downloaded'
  });
  dialog.addEventListener('click', function() {
    var Updater = require('lib/Updater');
    Updater.download(p.downloadUrl);
  });
  dialog.show();
}

Note: notice that input parameter to notifyNewUpdate() function is maintained. This allow developer to add more or remove unused parameter without breaking the function call.

Titanium ListView

Concept behind new Titanium ListView is similar to ModelViewViewModel (MVVM) pattern, where you have a set of data and you will map them to a view template

Let’s say you have this kind of data structure (model)

Person
- id {Number}
- name {String}
- photo {String} - URL
- message {String}

And you have an array of Person objects

var dataModels = [
  {
    id: 1,
    name: 'John',
    photo: 'http://example.com/img/john.jpg',
    message: 'Thank you'
  },
  {
    id: 2,
    name: 'Mary',
    photo: 'http://example.com/img/mary.jpg',
    message: 'Goodbye'
  },
  {
    id: 3,
    name: 'Chris',
    photo: 'http://example.com/img/chris.jpg',
    message: 'Hey there!'
  },
];

Now we want to map this array to a ListView, each Person object will use an ItemTemplate to produce a ListItem. First, define an ItemTemplate

var personTemplate = {
  childTemplates: [
    {
      type: 'Ti.UI.ImageView',
      bindId: 'photo',
      properties: {
        left: 5,
        top: 5,
        width: 50,
        height: Ti.UI.SIZE
      }
    },
    {
      type: 'Ti.UI.Label',
      bindId: 'name',
      properties: {
        left: 60,
        top: 5,
        height: 40,
        font: { fontSize: '18dp' },
        color: '#fff',
        wordWrap: false,
        ellipsize: true
      }
    },
    {
      type: 'Ti.UI.Label',
      bindId: 'message',
      properties: {
        left: 60,
        top: 45,
        font: { fontSize: '14dp' },
        color: '#eee'
      }
    }
  ]
};

A few things to note here. ItemTemplate defines views inside a ListItem, different from usual way we use add() method to add a view to another view. To compare how to define it with TableViewRow

var person = dataModels[i];
var row = Ti.UI.createTableViewRow({
  // to determine which row is being clicked
  itemId: person.id
});
row.add(Ti.UI.createImageView({
  image: person.photo,
  left: 5,
  top: 5,
  width: 50,
  height: Ti.UI.SIZE
}));
row.add(Ti.UI.createLabel({
  text: person.name,
  left: 60,
  top: 5,
  height: 40,
  font: { fontSize: '18dp' },
  color: '#fff',
  wordWrap: false,
  ellipsize: true
}));
row.add(Ti.UI.createLabel({
  text: person.message,
  left: 60,
  top: 45,
  font: { fontSize: '14dp' },
  color: '#eee'
}));

In childTemplates, is list of UI elements contain inside a ListItem. The way you define the element is by type & properties. bindId is the Person property (data model), which you want the UI to bind to – getting the data out and put it into the view.

Note that in Titanium documentation, there are ItemTemplate and ViewTemplate. ItemTemplate is used to generate a ListItem, while ViewTemplate is to generate other views, which specifically defined by the type property. See how to generate views in custom module, other than those defined in Ti.UI.* namespace.

However we cannot use dataModels array above directly onto ListView, we need to restructure it so it can be compatible with the UI element it is bound to. This process is called binding, which produce an array of view model (of type ListDataItem) that will be assigned to ListViewSection items property:

var viewModels = [
  {
    properties: { itemId: 1 },
    name: { text: 'John' },
    photo: { image: 'http://example.com/img/john.jpg' },
    message: { text: 'Thank you' }
  },
  {
    properties: { itemId: 2 },
    name: { text: 'Mary' },
    photo: { image: 'http://example.com/img/mary.jpg' },
    message: { text: 'Goodbye' }
  },
  {
    properties: { itemId: 3 },
    name: { text: 'Chris' },
    photo: { image: 'http://example.com/img/chris.jpg' },
    message: { text: 'Hey there!' }
  },
];

Notice that each Person properties have been changed, and by now it’s not considered data model any, but rather a view model. text and image are properties of Ti.UI.Label and Ti.UI.ImageView respectively, which you can use to bind the value to UI in the template you define earlier.

A ListView need to explicitly declare at least one ListSection, which acts as a place where you can set & append more ListItem.

var listView = Ti.UI.createListView({
  templates: {
    personTemplate: personTemplate
  },
  defaultItemTemplate: 'personTemplate'
});
var sections = [];
var section = Ti.UI.createListSection();
sections.push(section);
listView.setSections(sections);
win.add(listView);

You can add more template if you have more layout being used in a single ListView. Now load the dataSet into the ListView.

section.setItems(viewModels);

Load more items?

section.appendItems(viewModels);

Deeper visual tree of ItemTemplate

Use childTemplates on each UI element inside the template to customize it even more.

var personTemplate = {
  childTemplates: [
    {
      type: 'Ti.UI.ImageView',
      bindId: 'photo',
      properties: {
        left: 5,
        top: 5,
        width: 50,
        height: Ti.UI.SIZE
      }
    },
    {
      type: 'Ti.UI.View',
      properties: {
        layout: 'vertical',
        left: 60,
        top: 5
      },
      childTemplates: [
        {
          type: 'Ti.UI.Label',
          bindId: 'name',
          properties: {
            left: 0,
            top: 0,
            height: 40,
            font: { fontSize: '18dp' },
            color: '#fff',
            wordWrap: false,
            ellipsize: true
          }
        },
        {
          type: 'Ti.UI.Label',
          bindId: 'message',
          properties: {
            left: 0,
            top: 5,
            font: { fontSize: '14dp' },
            color: '#eee'
          }
        }
      ]
    }
  ]
};

Referring to template above, now you have this visual tree:

ListItem
 |__ ImageView
 |__ View
      |__ Label
      |__ Label

Events

For example, to add click event on image, add events property, specify an object with event name as key & callback as value

var template = {
  childTemplates: [
    {
      type: 'Ti.UI.ImageView',
      bindId: 'photo',
      properties: {
        left: 5,
        top: 5,
        width: 50,
        height: Ti.UI.SIZE
      },
      events: {
        click: function(e) {
          Ti.API.info('photo image clicked!');
        }
      }
    },{
      ...
    }
  ]
};

You can also use itemclick event of ListView to detect if a ListItem was clicked

listView.addEventListener('itemclick', function(e) {
  Ti.API.info('a ListItem was clicked!');

  // get which row is being clicked. See itemId property in viewModels above
  var person = dataModels.reduce(function(p, v) {
    if (v.id == e.itemId) {
      return v;
    }
    return p;
  });
});