【官方地址】
https://wiki.appcelerator.org/display/guides/Callbacks+and+Events+for+Loose+Coupling
我们在阅读了Appcelerator wiki中的“JavaScript最佳实践”之后都应该知道,使用全局变量或者破坏全局命名空间是编写高质量,可维护代码的禁忌。然而我们也知道旧的习惯是很难改的,我们在写代码时需要“this”来设值?只能创建一个全局变量来使用了。
通过这种方法解决问题最终他还会为我们带来麻烦。我们暂时忘记全局变量,将会有另外一种方法来得到同样的信息。
这里需要我们写在黄色便签上,让我们重视的有三点:
1、我们将要编写的是模块化代码(至少从现在开始)
2、基于事件的编程是很好的
3、只有在不得已的时候再使用全局变量
获取地理信息
这里,首先问题是什么?获取用户的当前地理位置信息。
这个处理会被异步执行,我们要更新的UI控件在另外一个文件中,当然,这是一个模块话的代码。
我们都知道通过调用API
Titanium.Geolocation.getCurrentPosition使用回调函数来让我们知道什么时候它找到了地理位置信息。
Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_BEST;
Titanium.Geolocation.distanceFilter = .25;
Ti.Geolocation.purpose = "Callbacks Are Your Friend";
// 调用API
Ti.Geolocation.getCurrentPosition(function(e) {
// 当获取位置信息出错时
if (e.error) {
Ti.API.error('geo - current position' + e.error);
return;
}
// 获取地理位置信息
Ti.App.info('got a location ',JSON.stringify(e));
});
把地理位置信息放在有用的地方
这里我们可以在回调函数的外边创建一个全局变量,来使用它获取信息。
Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_BEST;
Titanium.Geolocation.distanceFilter = .25;
Ti.Geolocation.purpose = "Callbacks Are Your Friend";
// 在回调中保存的坐标信息(全局)
var global_var_coords;
// 调用API
Ti.Geolocation.getCurrentPosition(function(e) {
// 当获取位置信息出错时
if (e.error) {
Ti.API.error('geo - current position' + e.error);
return;
}
// 获取地理位置信息
Ti.App.info('got a location ',JSON.stringify(e));
// 给全局变量赋值
global_var_coords = e.coords
});
但是这仅仅是帮助了我们,如果需要更新的UI控件跟回调处于同一个JS文件的情况。这不足以是我们写出模块化的代码。我们绝不能将UI代码和获取地理位置信息的逻辑代码混淆在一起。
通过事件监听把地理位置信息放在更好的地方
那么我们下来该做什么?首先是要摆脱全局变量,激发一个事件来指示地理位置信息已经成功被取到。
Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_BEST;
Titanium.Geolocation.distanceFilter = .25;
Ti.Geolocation.purpose = "Callbacks Are Your Friend";
// 全局监听
Ti.App.addEventListener('location.updated',function(coords){
Ti.API.debug(JSON.stringify(coords));
}
// 调用API
Ti.Geolocation.getCurrentPosition(function(e) {
// 当获取位置信息出错时
if (e.error) {
Ti.API.error('geo - current position' + e.error);
return;
}
// 获取地理位置信息
Ti.App.info('got a location ',JSON.stringify(e));
// 激发含有地理位置信息的事件
Ti.App.fireEvent('location.updated',e.coords);
});
这样,在应用的任何我们需要获取地理位置信息的地方,我们都可以创建一个监听来获得坐标信息。这样很棒,不再需要全局变量了!
也有另外一种方法:在回调中使用回调
我们在设备获取地理位置信息完成后调用一个函数。和激发一个事件一样,我们将调用一个函数,把我们从设备上获取到的地理位置信息坐标作为参数传给它。
//
// file_with_location.js
//
Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_BEST;
Titanium.Geolocation.distanceFilter = .25;
Ti.Geolocation.purpose = "Callbacks Are Your Friend";
/**
* @param {Object} _callback 地理位置信息查询完成后调用
*/
function currentLocation(_callback) {
// 调用API
Ti.Geolocation.getCurrentPosition(function(e) {
// 当获取位置信息出错时
if (e.error) {
Ti.API.error('geo - current position' + e.error);
// to keep it simple, just returning null, could be
// error information
if (_callback) {
_callback(null);
}
return;
}
// 获取地理位置信息
Ti.App.info('got a location ',JSON.stringify(e));
// 激发含有地理位置信息的事件
Ti.App.fireEvent('location.updated',e.coords);
// 用坐标调用回调函数
if (_callback) {
_callback(e.coords);
}
});
}
在我们代码的其他地方,我们需要获得信息后把信息更新到UI控件上。
Ti.include('file_with_location.js');
// 打开一个窗口
var window = Ti.UI.createWindow({
backgroundColor:'white'
});
var coordsLbl = Titanium.UI.createLabel({
text:"NO LOCATION",
left: 10,
width: 240,
height: 'auto',
top: 20,
textAlign: 'left',
});
window.add(coordsLbl);
window.open();
// 执行回调获取地理位置信息, gpsCallback方法被传入获取地理位置信息的方法
// 他将在获取到地理位置信息伙子出错的时候被调用
currentLocation(gpsCallback);
/**
* @param {Object} _coords 地理位置信息的经纬度值
*/
function gpsCallback(_coords) {
if (_coords) {
coordsLbl.text = String.format("lon: %s\n lat: %s ", _coords.longitude + "", _coords.latitude + "");
} else {
coordsLbl.text = "NO LOCATION";
}
}
Kevi说模块化是最好的
Kevin Whinnery: Write Better JavaScript:
video|
slides
好,我们现在已经在包含文件中有了GPS代码,它和UI代码分离,我们可以在任何需要获取地理位置信息的地方调用它,或者是一个事件,或者是一个回调函数。但是,我们还是没有做到-模块化CommonJS,还有“requires”的一切。
我们想做一个好的Appcelerator市民,编写出比Kitchen-sink更强大的代码。KitchenSink 毕竟只是一个演示API功能的,它并不是最好的例子。
这里让我们把我们的地理位置信息文件转化成一个模块。只需要在函数名之前加一个“exports”,并保证其公有。
//
Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_BEST;
Titanium.Geolocation.distanceFilter = .25;
Ti.Geolocation.purpose = "Callbacks Are Your Friend";
// PUBLIC FUNCTION
/**
* @param {Object} _callback 地理位置信息查询完成后调用
*/
exports.currentLocation = function(_callback) {
Titanium.Geolocation.getCurrentPosition(function(e) {
if(e.error) {
alert('error ' + JSON.stringify(e.error));
// 为了保持一致,返回null
if(_callback) {
_callback(null);
}
return;
}
Ti.App.fireEvent('location.updated', e.coords);
if(_callback) {
_callback(e.coords);
}
});
};
在我们的ui.js文件的创建窗口的位置,我们需要加载这个含有地理位置信息取得的模块。完整的例子,我们把文件命名为“maps.js”。我们需要添加一下语句:
引用
require
记住:在使用requie时不需要包含".js"扩展名,他不需要。
var maps = require('lib/maps');
当你调用方法时:
// do the callback to get current location
maps.currentLocation(gpsCallback);
这里是完整的ui.js:
// private vars
var mainWindow, callback_label_coords;
var styles = require('styles');
var maps = require('lib/maps');
/**
* @param {Object} args properties for the window
*/
exports.AppWindow = function(args) {
var instance, event_label, callback_label;
// create window
instance = Ti.UI.createWindow(args);
// make callback label
callback_label = Ti.UI.createLabel(styles.callback_label);
instance.add(callback_label);
callback_label_coords = Ti.UI.createLabel(styles.coords_label);
instance.add(callback_label_coords);
// make event listener label
event_label = Ti.UI.createLabel(styles.event_label);
instance.add(event_label);
event_label_coords = Ti.UI.createLabel(styles.coords_label);
instance.add(event_label_coords);
// create event Listener
Ti.App.addEventListener('location.updated', function(_coords) {
event_label_coords.text = String.format("longitude: %s\n latitude: %s ", _coords.longitude + "", _coords.latitude + "");
});
// do the callback to get current location
maps.currentLocation(gpsCallback);
// save the window
mainWindow = instance;
return instance;
};
/**
* @param {Object} _coords lat, lon values from locationo
*/
function gpsCallback(_coords) {
callback_label_coords.text = String.format("longitude: %s\n latitude: %s ", _coords.longitude + "", _coords.latitude + "");
}
总结
使用回调和事件对你的代码是有益的。它减少耦合,更好的分离业务逻辑和表现层。从现在开始,我们将在应用开发中更加强化模块化代码,这将放映在不久以后我们带给你所有的内容之中。
Keep coding strong!
代码
CallbacksAreYourFriend on Github