Global logging using Ti.App.Listener

There is built-in ability of Titanium to fire and listen to application wide events. This powerful feature can be a perfect fit for creating loosely-coupled components. This pattern can provide a decoupled logging approach, which is helpful for specific situations such as analytics, logging, and process monitoring modules.

This recipe details how Ti.App.Listener can be used to create a decoupled re-useable application component. The following screenshot demonstrates this recipe running on both the iPhone and Android platforms:

Global logging using Ti.App.Listener

Getting ready

Adding the CommonJS modules used in this recipe is straightforward and consists of copying the logger.js and mainWin.js files into the root of our Titanium project as shown in the following screenshot:

Getting ready

How to do it...

Application-level events allow you to implement a publish/subscribe pattern globally in your app, even across execution contexts. By simply adding a listener such as the following, you can receive messages fired from anywhere in your app:

Ti.App.addEventListener('app:myEvent', myFunctionToHandleThisEvent);

Firing a custom event in Titanium is easy. You simply use the Ti.App.fireEvent and provide the event name and an optional parameter payload. This example shows how to call the app:myEvent listener we defined earlier.

Ti.App.fireEvent('app:myEvent',"My parameter objects");

Tip

It is recommended that you name your events using a descriptive convention. For example, app:myEvent describes that this is an application event and is defined in my app.js file.

Designing global logging using events

The following recipes show how to use application-level custom events to implement logging across the different contexts of our app.

Defining our app.js

In the app.js, we define our application namespace and import the logger and UI CommonJS modules.

//Create our application namespace
var my = {
  ui:{
    mainWindow : require('mainWin').createWindow()
  },
  logger : require('logger')
};

Next in our app.js, the setup method is called on the logger module. This ensures our database logging tables are created.

//Run setup to create our logging db
my.logger.setup();

The application-level listener is then defined in our app.js. This listener will wait for the app:log event to be fired and then call the logger's add method with the payload provided.

//Add a global event to listen for log messages
Ti.App.addEventListener('app:log',function(e){
  //Provide Log Message to CommonJS Logging Component
  my.logger.add(e);
});

//Open our sample window
my.ui.mainWindow.open();

The logging module

The following code snippet demonstrates how to create the basic CommonJS module, logger.js, used in our global listener recipe. This module has two methods; setup, which creates our database objects, and add, which the listener calls to log our messages.

Create a constant with the logging database name.

var LOG_DB_NAME = "my_log_db";

Create the setup module-level method. This is used to create the LOG_HISTORY table, which will later be used to record all log statements.

exports.setup=function(){
  var createSQL = 'CREATE TABLE IF NOT EXISTS LOG_HISTORY '; 
  createSQL +='(LOG_NAME TEXT, LOG_MESSAGE TEXT, ';
  createSQL += 'LOG_DATE DATE)';
  //Install the db if needed
  var db = Ti.Database.open(LOG_DB_NAME);
  //Create our logging table if needed
  db.execute(createSQL);
  //Close the db
  db.close();
};

Create the add module-level method. This method is used to record the information to be added to the log table.

exports.add=function(logInfo){
  var insertSQL ="INSERT INTO LOG_HISTORY ";
  insertSQL +=" (LOG_NAME,LOG_MESSAGE,LOG_DATE)"; 
  insertSQL +=" "VALUES(?,?,?)";
  var db = Ti.Database.open(LOG_DB_NAME);
  //Create our logging table if needed
  db.execute(insertSQL,logInfo.name,logInfo.message, 
  new Date());
  //Close the db
  db.close();
};

Bringing it all together

The following sections show the contents of our mainWin.js module. This module returns a window with a single button that when pressed fires our logging event.

Window and module variable setup

The fetchWindow function returns a simple window demonstrating how to fire an application-level event. To demonstrate, a new message is sent each time, and we add a module level variable named _press_Count, which increments with each click.

Create the module-level variable _press_Count to record the number of times addLogButton has been pressed.

var _press_Count = 0;

The fetchWindow method returns a Ti.UI.Window containing the UI elements for this recipe.

exports.fetchWindow=function(){

A Ti.UI.Window is created for all of our UI elements to be attached.

  var win = Ti.UI.createWindow({
    backgroundColor:'#fff'
  });

The addLogButton Ti.UI.Button is created. This button will be used to trigger the Ti.App.fireEvent used to demonstrate global listeners in this recipe.

  var addLogButton = Ti.UI.createButton({
    title:"Fire Log Event", top:180, 
    left:5,right:5, height:50
  });

Firing the application-level event

On clicking on the addLogButton button, the _press_Count variable is increased by one and a logging object is created. The following code demonstrates how the Ti.App.fireEvent method is called for the app:log event and a JavaScript object containing our logging details is provided. The listener we defined in our app.js will then receive this message and log our results.

  addLogButton.addEventListener('click',function(e){		

The first action taken after the user taps the addLogButton is to increase the _pressCount by one.

    _press_Count ++;

Next the logObject containing information to be submitted for logging is created.

    var logObject = {
      name:'test log',
      message:'example message ' + 
      _press_Count
    };

Finally, the Ti.App.fireEvent is called for the app:log event. The logObject is also provided as a parameter when calling this application global event.

    Ti.App.fireEvent('app:log',logObject);
  });    
  win.add(addLogButton);
    
  //Return window
  return win;
};

Note

App logging is just one of the many examples of how you can use application-level events to decouple your app's components. This pattern will be used several times over the course of this book when decoupled component interaction is required.

There's more...

Since application-level listeners are globally scoped, you need to take caution where and when they are defined. A general rule of thumb is to define application-level listeners in an area of your app that is always available and never reloaded, such as your app.js, CommonJS file which is only loaded once, or another bootstrapping method.

If you must define them within a window or other module that is loaded repeatedly, make sure you remove the listener when the object is no longer needed. To remove the event listener, you need to call the Ti.App.removeEventListener method with the same arguments used on creation. The following snippet shows how to remove the app:myEvent listener created earlier:

Ti.App.removeEventListener('app:myEvent', myFunctionToHandleThisEvent);

Tip

If you do not remove a listener, all associated JavaScript objects will not be eligible for garbage collection, often resulting in a memory leak.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.253.239