Creating [object] in a different context than the calling function.

Creating [object] in a different context than the calling function.

This warning occured when a JS callback function is passed to Objective-C as KrollCallback and then executed on non-JS thread.

KrollCallback *callback = [args objectForKey@"callback"];

[OneSignal initWithLaunchOptions:[TiApp app].launchOptions appId:appId handleNotificationAction:^(OSNotificationResult *result) {
    [callback call:@[] thisObject:nil];
}];

Problem with this warning is, if the JS callback create Ti.Network.HTTPClient instance, then that instance is null.

function callback() {
    var http = Ti.Network.createHTTPClient();
    http.open('GET', getUrl()); // JS error! http is null
    http.send();
}

To fix, get krollContext instance of current module/proxy and execute callback inside invokeBlockOnThread

// For TiModule / TiProxy descendants
KrollContext *context = [self.executionContext krollContext];

// For TiUIView descendants
KrollContext *context = [self.proxy.executionContext krollContext];

// invoke
[context invokeBlockOnThread:^{
    [callback call:@[] thisObject:nil];
}];

Titanium app hex color value with alpha channel

Color values are represented in hexadecimal value:

#000000

  • 0 – red, 0 – green, 0 – blue
  • color = black

#ffffff

  • 255 – red, 255 – green, 255 – blue
  • color = white

‘ff’ in hexadecimal is 255 in decimal, (2 ^ 8) – 1 = 255.

In CSS, to represent color with alpha channel, we can use the rgba() syntax:

rgba(0, 0, 0, 0.6)

  • 0 – red, 0 – green, 0 – blue
  • black with 60% opacity

In Titanium, rgba() syntax only available on iOS, but hex value also can be used to represent alpha channel, and it supported by both iOS & Android

#ff000000

  • 0 – red, 0 – green, 0 – blue
  • ff – 255 / 100% opacity

#90ffcc00

  • 255 – red, 204 – green, 0 – blue
  • 90 – 144 / 56% opacity

To easily maintain colors in app, this function is to transform rgba value into Titanium hex color format

function rgbaToHex(r, g, b, a) {
    var toHex = function(n) {
        return ('00' + (n | 0).toString(16)).slice(-2);
    };
    return '#' + toHex(((a * 100) / 100) * 255) + toHex(r) + toHex(g) + toHex (b);
}

Explanation:

  • (n | 0) is shortcut for parseInt(), to ensure the value passed in is integer. We don’t want the hex color value to have decimal point, e.g: #2.4ccc
  • .toString(16) is Number object function (not Object.toString()) to convert number into hexadecimal format
  • ('00' + value).slice(-2) is to add string padding to the left of the string, so that it will always have 2 characters. We don’t want the value to have one character, #0ccff is invalid value

Usage:

var view = Ti.UI.createView({
    backgroundColor: rgbaToHex(255, 204, 0, 0.5)
});

Lazyloading JS modules in Titanium app

In NodeJS project, usually modules are loaded at the beginning of the file:

var fs = require('fs');
var path = require('path');
var express = require('express');

When this NodeJS application being run, it loads all of the dependencies & start executing the program. In large application, there will be delay before the application can start operating, because of the dependencies loading.

For desktop or server application, this won’t be much issue, but in mobile app like Titanium, if it loads the whole dependencies during app launch, it might cause unresponsive app & consume large memory, even when those modules haven’t being used yet.

Another problem is there might be circular dependencies issue, in which module A require module B, but module B also require module A, and this lead to module A variable in B to become an empty object. Example:

// db.js - database module
var Person = require('model/Person');
Person.setup();

// Person.js - data model
var db = require('db');
db.execute('sql'); // TypeError, undefined is not a function

Restructuring the code flow is one method to fix, but in my experience, it cause a lot of repeated code

// Person.js
var Person = {};
Person.setup = function() {
     var db = require('db');
};

Person.getById = function() {
     var db = require('db');
};

Person.getAll = function() {
     var db = require('db');
};

Because of this, I use the lazyloading approach & make use of JS object getter to both solve the problem & make the code cleaner. The idea is to have a global variable, which will be included in each of the modules we have in a Titanium app, and this global object holds a reference to every modules we packaged into the app. This reference will then call a getter to do require() and return the actual module to the caller.

In addition, modules are categorized into folders which can act as namespace, to eliminate class name conflict

// globals.js
var g = {};

var modules = [
     'window/MainWindow',
     'ui/ContactList',
     'ui/ContactListItem',
     'model/Contact',
     'core/Db',
     'core/Http'
];

modules.forEach(function(mod) {
     var parts = mod.split('/');
     var namespace = parts[0];
     var className = parts[1];
     var obj = g[namespace];
     if (!obj) {
          obj = {};
     }
     Object.defineProperty(obj, className, {
          get: (function(path) {
               return function() {
                    return require(path);
               };
          })(mod),
          set: function() {}
     });
});

module.exports = g;

Now, the Person model class can be refactored like below:

// Person.js
var g = require('globals');
var Person = {};
Person.setup = function() {
     g.core.Db.execute('sql');
};
Person.getAll = function() {
     g.core.Db.execute('sql');
};

This is just a basic implementation of the idea, and you can extend it to support subnamespace & native module.

Webview evalJS return null in Android 4.2.2

I have a webview that points to external URL

var webview = Ti.UI.createWebView({
	url: 'http://example.com/test.html'
});

In test.html I have a global variable

<script type="text/javascript">
var myvar = JSON.stringify({ status: true });
</script>

On webview onload event, evalJS('myvar') return null, and inside log message got “Timeout waiting to evaluate JS”. After a few days try & error, test and compare, finally I found the culprit is within tiapp.xml file.

My tiapp.xml has a customized <android> section

<android xmlns:android="http://schemas.android.com/apk/res/android">
  <tool-api-level>17</tool-api-level>
  <manifest android:installLocation="auto" android:versionCode="1" android:versionName="1.0.0">
    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/>
    <application>
      <activity android:configChanges="keyboardHidden" android:name="org.appcelerator.titanium.TiActivity" android:screenOrientation="portrait"/>
    </application>
  </manifest>
  <services>
    <service type="standard" url="lib/service/clear.js"/>
  </services>
</android>

It turns out that <uses-sdk> part is the one causes this bug. Removing the line <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/> fix this bug and I can retrieve myvar values using evalJS() again.

Indirect code execution flow

Intro: we have an Android app, with typical main and detail window structure.

Let’s see this situation: when user tap a button on main window and then open a detail window, later when user closes the detail window, it needs to update the main window UI.

Here, we have two method of how to update the UI – proactive / direct way, or passive / indirect way.

First, there are several point during detail window closing process, which we can run the function to update the main window UI.

  • when user press back button on detail window
  • when detail window close event
  • when main window resumed

Direct way – when running the function to update main window UI during the 1st and 2nd point above.

// in detail window class

detailWindow.addEventListener('androidback', function() {
	mainWindow.updateUI();
	detailWindow.close();
});

// or

detailWindow.addEventListener('close', function() {
	mainWindow.updateUI();
});

Some disadvantages for this method:

  • detail window need to keep a reference to main window.
  • if updateUI() function take some time, then closing detail window will be delayed

Therefore, to ensure responsiveness of the app, we need to utilize indirect way of executing the code. When main window resume, we run the code to update the UI. But, what if we need to update the UI only when user close the detail window? Here, we need a state variable (variable that keeps track of a state).

// in main window class

var detailWindowOpened = false;
btn.addEventListener('click', function() {
	detailWindowOpened = true;
	detailWindow.open();
});

detailWindowOpened is the state variable, it tracks whether detail window has been opened or not.

// in main window class

mainWindow.activity.addEventListener('resume', function() {
	if (detailWindowOpened) {
		updateUI();
		detailWindowOpened = false;
	}
});

Then, when main window resume, it will automatically update its UI. So here, we don’t need to keep a reference of main window inside detail window class, and closing detail window won’t be delayed.

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();