原文:http://wiki.appcelerator.org/display/guides/Working+with+Local+Data
* 要点
* 使用本地数据
o 选用哪种类型的数据存储?
* App属性
o 读写属性
o 以JSON形式,把JS对象存储在属性中
* 文件系统存储
o 对象
o 属性
o 方法
o 写文件
o 读文件
o 移除文件
o 完整代码
* SQLite 数据库
o SQL基础和更多阅读
o 创建数据库
o 准备好数据库
+ 把数据库包含在App包中
+ 从远程下载数据库
o 存数据
o 读数据
o 更新数据
o 关闭数据库和数据集
* 本地存储的不同模式,何时使用
* 怎样用程序属性
* 怎样从本地文件系统中存取数据
* 怎样和本地SQLite 数据库交互
var window = Titanium.UI.createWindow({ backgroundColor:'#999' }); var myArray = [ { name:'Name 1', address:'1 Main St'}, {name:'Name 2', address:'2 Main St'}, {name:'Name 3', address:'3 Main St'}, {name:'Name 4', address:'4 Main St' } ]; Ti.App.Properties.setString('myString','This is a string'); Ti.App.Properties.setInt('myInt',10); Ti.App.Properties.setBool('myBool',true); Ti.App.Properties.setDouble('myDouble',10.6); Ti.App.Properties.setList('myList',myArray); // ********************************************** // Notice the use of the second argument of the get* methods below // that would be returned if no property exists with that name // ********************************************** Ti.API.info("String: "+Ti.App.Properties.getString('myString','This is a string default')); Ti.API.info("Integer: "+Ti.App.Properties.getInt('myInt',20)); Ti.API.info("Boolean: "+Ti.App.Properties.getBool('myBool',false)); Ti.API.info("Double: "+Ti.App.Properties.getDouble('myDouble',20.6)); Ti.API.info("List: "+Ti.App.Properties.getList('myList')); window.open();执行输出:
String: This is a string Integer: 10 Boolean: true Double: 10.600000381469727 List: { 'address' : '1 Main St' 'name' : 'Name 1', }, { 'address' : '2 Main St' 'name' : 'Name 2', }, { 'address' : '3 Main St' 'name' : 'Name 3', }, { 'address' : '4 Main St' 'name' : 'Name 4', }
var window = Titanium.UI.createWindow({ backgroundColor:'#999' }); var weatherData = { "reports" : [ { "city": "Mountain View", "condition": "Cloudy", "icon": "http://www.google.com/weather/cloudy.gif" }, { "city": "Washington, DC", "condition": "Mostly Cloudy", "icon": "http://www.google.com/weather/mostly_cloudy.gif" }, { "city": "Brasilia", "condition": "Thunderstorm", "icon": "http://www.google.com/weather/thunderstorm.gif" } ] }; Ti.App.Properties.setString('myJSON', JSON.stringify(weatherData)); var retrievedJSON=Ti.App.Properties.getString('myJSON', 'myJSON not found'); Ti.API.info("The myJSON property contains: " + retrievedJSON); window.open();测试输出:
The myJSON property contains: {"reports":[{"icon":"http:\/\/www.google.com\/ig\/images\/weather\/cloudy.gif","condition":"Cloudy","city":"Mountain View"},{"icon":"http:\/\/www.google.com\/ig\/images\/weather\/mostly_cloudy.gif","condition":"Mostly Cloudy","city":"Washington, DC"},{"icon":"http:\/\/www.google.com\/ig\/images\/weather\/thunderstorm.gif","condition":"Thunderstorm","city":"Brasilia"}]}取值时再用JSON.parse()还原成JS对象:
var myObject = JSON.parse(Ti.App.Properties.getString('myJSON'));
var dataToWrite = {"en_us":{"foo":"bar"}};接着创建目录:
// NOTE: use applicationDataDirectory for writes!! var newDir = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory,'mydir'); newDir.createDirectory(); Ti.API.info('Path to newdir: ' + newDir.nativePath);现在有了特定的applicationDataDirectory作为新目录。程序可以对其读写操作。通常都得这样做。
var newFile = Titanium.Filesystem.getFile(newDir.nativePath,'newfile.json');这样就添加了空白文件,但最好加点数据。初始化 dataToWrite 对象。和前面App属性做的一样。用Titanium.JSON。用JS对象写:
//Stringify the JavaScript object we created earlier and write it out to the new file newFile.write(JSON.stringify(dataToWrite));
var newFile = Titanium.Filesystem.getFile(newDir.nativePath,'newfile.json'); var resources = JSON.parse(newFile.read().text); resources.en_us.foo = 'baz'; //bar becomes baz newFile.write(JSON.stringify(resources));
//We already have references to the file and directory objects. //We just need to call their cooresponding delete methods. newFile.deleteFile(); newDir.deleteDirectory();
var dataToWrite = {"en_us":{"foo":"bar"}}; //NOTE: remember to use applicationDataDirectory for writes var newDir = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory,'mydir'); newDir.createDirectory(); Ti.API.info('Path to newdir: ' + newDir.nativePath); var newFile = Titanium.Filesystem.getFile(newDir.nativePath,'newfile.json'); //Stringify the JavaScript object we created earlier and write it out to the new file newFile.write(JSON.stringify(dataToWrite)); var newFile = Titanium.Filesystem.getFile(newDir.nativePath,'newfile.json'); Ti.API.info('JSON.parse(newFile.read().text).en_us.foo = ' + JSON.parse(newFile.read().text).en_us.foo); var resources = JSON.parse(newFile.read().text); resources.en_us.foo = 'baz'; //bar becomes baz newFile.write(JSON.stringify(resources)); Ti.API.info('JSON.parse(newFile.read().text).en_us.foo = ' + JSON.parse(newFile.read().text).en_us.foo); //We already have references to the file and directory objects. //We just need to call their cooresponding delete methods. newFile.deleteFile(); newDir.deleteDirectory();
var db = Ti.Database.open('weatherDB');这将创建名为weatherDB的文件。最好加上.sqlite或者.db后缀名,当然这不是必须的。
var db = Ti.Database.install('/mydata/weatherDB', 'weatherDB');这里,weatherDB在Resources/mydata/ directory目录下初始,再复制到App的数据库目录中。
db.execute('CREATE TABLE IF NOT EXISTS city (id INTEGER PRIMARY KEY, name VARCHAR(16) NOT NULL, continent VARCHAR(16) NOT NULL, temp_f VARCHAR(4), temp_c VARCHAR(4), condition_id INTEGER NOT NULL)'); db.execute('CREATE TABLE IF NOT EXISTS condition (id INTEGER PRIMARY KEY, summary VARCHAR(16) NOT NULL, icon TEXT NOT NULL)');IF NOT EXISTS部分是标准的SQLite 语法,来确保不会重写覆盖表。以上这些,就是SQLite操作的常用套路,用来防止因为丢失数据库或数据表而无法启动App的情况发生。
buttonInstallRemote.addEventListener('click', function(){ var fileWeatherDB = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory,'../databases/'+filename); var c = Ti.Network.createHTTPClient(); c.setTimeout(10000); c.onload = function(e){ fileWeatherDB.write(this.responseData); Ti.API.info("ONLOAD = "+e); Ti.UI.createAlertDialog({title:'Info', message:'Database installed', buttonNames: ['OK']}).show(); }; c.onerror = function(e){ Ti.UI.createAlertDialog({title:'Error', message:'Error: ' + e.error, buttonNames: ['OK']}).show(); }; c.open('GET',"http://wiki.appcelerator.org/download/attachments/6261518/weatherDB"); c.send(); });
db.execute('INSERT INTO city (name,continent,temp_f,temp_c,condition_id) VALUES (?,?,?,?,?)',importName,importContinent,importTempF,importTempC,dbConditionId);记住SQL的特性:一次只能加一条记录,一次只能加一个表。
var cityWeatherRS = db.execute('SELECT id,name,continent FROM city'); while (cityWeatherRS.isValidRow()) { var cityId = cityWeatherRS.fieldByName('id'); var cityName = cityWeatherRS.fieldByName('name'); var cityContinent = cityWeatherRS.fieldByName('continent'); Ti.API.info(cityId + ' ' + cityName + ' ' + cityContinent); cityWeatherRS.next(); } cityWeatherRS.close();像标准SQL一样,可以把数据连接起来,下面返回city记录,和weather 记录。
db.execute('SELECT city.id,name,cond.id,cond.summary,cond.icon FROM city LEFT JOIN condition cond WHERE city.condition_id = cond.id');或者仅返回天气是"Partly Cloudy"的行:
var cityWeatherRS = db.execute('SELECT city.id AS city_id,name,cond.id AS cond_id,cond.summary,cond.icon FROM city LEFT JOIN condition cond WHERE city.condition_id = cond.id WHERE cond.summary=?', "Partly Cloudy");注意city.id和cond.id使用了别名。因为如果你写着这样: fieldByName(id). 仅仅传进名字的参数, fieldByName() 方法不可能区分它们。数据集代码如下:
while (cityWeatherRS.isValidRow()) { var cityId = cityWeatherRS.fieldByName('city_id'); var cityName = cityWeatherRS.fieldByName('name'); var cityConditionId = cityWeatherRS.fieldByName('cond_id'); var cityConditionSummary = cityWeatherRS.fieldByName('summary'); var cityConditionIcon = cityWeatherRS.fieldByName('icon'); Ti.API.info(cityId + ' ' + cityName + ' ' + cityConditionId + ' ' + cityConditionSummary + ' ' + cityConditionIcon); cityWeatherRS.next(); } cityWeatherRS.close();
db.execute('UPDATE condition SET icon=? WHERE id=?',importIcon,dbConditionId);
db.close();开启数据集不是一个大问题,但最好养成习惯关闭它以释放系统资源。
cityWeatherRS.close();(完)