zoukankan      html  css  js  c++  java
  • Objective of the Guidelines

    Mobile Best Practices - Documentation & Guides - Appcelerator Wiki

    Objective of the Guidelines

    Titanium Mobile is a relatively young and constantly changing platform. The best practices delineated here are subject to change, and may not encompass all the knowledge necessary to build a great Titanium application. The goal of this document is to lay out, at a high level, what are currently known to be good (and some bad) practices in Titanium Mobile (and JavaScript in general) applications.

    The Guidelines in Brief

    Titanium Mobile applications should:

    • Be careful not to pollute the global object
    • Run in a single JavaScript context
    • Be modular and object-oriented using CommonJS modules
    • Defer loading JavaScript files until absolutely needed
    • Take reasonable steps to manage memory usage and avoid memory leaks

    Seriously? That's it?

    Yes. There are many different ways to build an application - using an MVC or MVVM architecture, maybe a framework of your own choosing or one you've built yourself. The guidelines in this document are considered the bedrock requirements for a stable and performant Titanium Mobile application. Your own application structures, business logic, and conventions may vary, and we do not endeavor to impose any such conventions in this document.

    The Guidelines Explained

    Applications shall take care not to pollute the global object

    In JavaScript, there is a global object for the application - any variables declared in the global scope will become properties of this global object. In Titanium Mobile, the global object is available as this in app.js.

    Any variables declared in app.js shall be globally available in the entire application. This can cause collisions if external scripts are included into this context via Ti.include. For this and other reasons, use of Ti.include is discouraged, and will be replaced in the future by the CommonJS module specification's require function.

    To prevent polluting the global object in app.js, you must use the only scope available in JavaScript - a closure. A simple way to use a closure to avoid polluting the global scope is to use a self-calling function:

    app.js
    (function() {
      var privateData = 'tee hee! can\'t see me!';
    })();
    alert(privateData); //undefined in the global scope

    When separating code into external files, the require function provided by the CommonJS module spec should be used to inject additional functionality into the global scope or the scope of a module. This technique will be explained later on in the document.

    Applications shall run in a single JavaScript context

    In the previous section, we discussed the global scope of a JavaScript application. With Titanium Mobile, it is possible to create a window with a url property set to a path to a Javascript file (relative to the current file). When the window's open method is called, the associated JavaScript file is evaluated, creating a secondary "execution context" and, thus, a new scope. Except in rare cases, this multiple active JavaScript environment should be avoided.

    These multiple execution contexts cause problem because no scope has visibility of any other, meaning that sharing data between contexts is not possible without the ungainly use of application-level custom events (using Titanium.App addEventListener and fireEvent). They can also lead to circular references and likely memory leaks. There are lifecycle issues too, where it becomes unclear when the code for a given JavaScript file has been evaluated.

    While there are a few reasonable use cases for this approach, such as an "app within an app" where every new window requires a "clean slate" with no dependencies on the global context, normally windows with URLs should not be used.

    Applications shall be modular and object-oriented using CommonJS modules

    Separation of concerns should be enforced by dividing application logic into separate JavaScript files and objects, adhering to the principle of cohesion. Not all JavaScript applications need to use instantiable objects - but all should make use of the CommonJS module standard. The CommonJS module spec provides for sandboxed JavaScript modules with a well-defined public interface, exposed as the exports object within a CommonJS module file. A sample usage of the CommonJS module spec in Titanium Mobile is below.

    A simple CommonJS module, in lib/maths.js in the Resources directory
    var privateData = 'private to the module\'s sandbox, not available globally';
     
    //any property attached to the exports object becomes part of the module's public interface
    exports.add = function() {
      var result = 0;
      for (var i = 0, l = arguments.length;i<l;i++) {
        result = result+arguments[i];
      }
      return result;
    };
    Sample usage in app.js
    var maths = require('lib/maths');
    var sum = maths.add(2,2,2,2,2);
    //sum is 10

    An instantiable object in a CommonJS module would look like this:

    lib/geo.js - A module containing instantiable objects
    function Point(x,y) {
      this.x = x;
      this.y = y;
    }
     
    function Line(start,end) {
      this.start = start;
      this.end = end;
    }
     
    //create public interface
    exports.Point = Point;
    exports.Line = Line;
    Sample usage in app.js
    var geo = require('lib/geo');
     
    var startPoint = new geo.Point(1,-5);
    var endPoint = new geo.Point(10,2);
     
    var line = new geo.Line(startPoint,endPoint);

    When creating objects in Titanium Mobile applications, one must adhere to general programming best practices, including object orientation. In this section, we will go into one more example. A common need in Titanium Mobile applications is to create custom user interface components. A common practice for extending built-in objects is parasitic inheritance. While a perfectly valid practice in standard JavaScript, it can result in unpredictable behavior in Titanium Mobile when using proxy objects (objects returned by Ti.UI.createView and similar). A reasonable approach to creating a custom component would be to associate a proxy with a normal JavaScript object, as in the below:

    ui/ToggleBox.js - A custom check box
    function ToggleBox(onChange) {
      this.view = Ti.UI.createView({backgroundColor:'red',height:50,50});
     
      //private instance variable
      var active = false;
     
      //public instance functions to update internal state, execute events
      this.setActive = function(_active) {
        active = _active;
        this.view.backgroundColor = (active) ? 'green' : 'red';
        onChange.call(instance);
      };
     
      this.isActive = function() {
        return active;
      };
     
      //set up behavior for component
      this.view.addEventListener('click', function() {
        this.setActive(!active);
      });
    }
    exports.ToggleBox = ToggleBox;
    Sample usage in app.js
    var win = Ti.UI.createWindow({backgroundColor:'white'});
    var ToggleBox = require('ui/ToggleBox').ToggleBox;
     
    var tb = new ToggleBox(function() {
      alert('The check box is currently: '+this.isActive());
    });
    tb.view.top = 50;
    tb.view.left = 100;
     
    win.add(tb.view);

    Applications shall defer script loading until absolutely needed

    One of the bottlenecks of a Titanium application is JavaScript evaluation. This is particularly the case for Android, although the V8 runtime provides substantial improvements for this issue compared with Rhino. For that reason, to speed the startup and responsiveness of your application, the developer should avoid loading scripts until they are absolutely needed. As in the following application, which has three windows to be opened in succession on a click (touch) event, note that the dependent JavaScript for each window is not loaded until absolutely necessary.

    Lazy script loading in app.js
    //muse be loaded at launch
    var WindowOne = require('ui/WindowOne').WindowOne;
     
    var win1 = new WindowOne();
    win1.open();
     
    win1.addEventListener('click', function() {
      //load window two JavaScript when needed...
      var WindowTwo = require('ui/WindowTwo').WindowTwo;
      var win2 = new WindowTwo();
      win2.open();
      win2.addEventListener('click', function() {
        //load window three JavaScript when needed...
        var WindowThree = require('ui/WindowThree').WindowThree;
        var win3 = new WindowTwo();
        win3.open();
      });
    });

    Applications shall take reasonable steps to manage memory

    In very large applications, it occasionally becomes necessary to force Titanium to clean up resources. To do this, the developer has a few things to track:

    • the windows can be closed. This should cause Titanium to free up the resources reserved for the view objects added to the window.
    • remove global event handlers when they are no longer needed. References to objects within these closures will be retained otherwise - this is a common memory leak in large JavaScript applications in the browser also. Some common global event handlers include Ti.App.addEventListener (global messaging system), geolocation events, and orientation change events
    • proxy objects can be set to null. This ensures that these objects are garbage collected to release the associated native objects.

    Example:

    Nulling out object references
    var win = Ti.UI.createWindow();
     
    var myBigView = new BigView();
    win.add(myBigView.view);
    win.open();
     
    //...at some point in the future...
    win.remove(myBigView);
    myBigView = null; //will cause view to be GC'ed
  • 相关阅读:
    JSON排序
    iOS常用控件尺寸大集合
    Android 平台下Ftp 使用模拟器需要注意的问题
    PhoneGap Html5 App 横竖屏切换自动退出
    加减密 DES
    入学测试题
    黑马程序员——JAVA基础之反射
    黑马程序员——JAVA基础之网络编程
    黑马程序员——JAVA基础之正则表达式,网络爬虫
    黑马程序员——JAVA基础之GUI
  • 原文地址:https://www.cnblogs.com/lexus/p/2433391.html
Copyright © 2011-2022 走看看