NativeScript是用于使用XML,CSS和JavaScript构建跨平台本机移动应用程序的框架。 在本系列中,我们正在尝试使用NativeScript应用程序可以执行的一些很酷的操作:地理位置和Google Maps集成,SQLite数据库,Firebase集成和推送通知。 在此过程中,我们正在构建一个具有实时功能的健身应用程序,它将使用这些功能中的每一个。
在本教程中,您将学习如何将SQLite数据库集成到应用程序中以在本地存储数据。 具体来说,我们将存储在上一教程中收集的步行会议数据。
您将要创造的
从上一教程中摘录,您将添加一个标签视图以显示应用程序的不同部分。 以前,我们的应用程序只有“ 跟踪”页面,因此我们不需要标签。 在这篇文章中,我们将添加“ 步行”页面。 此页面将显示用户的步行会话。 每当用户跟踪其步行会话时,都会在此处添加一个新的数据点。 还有一个清除数据的功能。
最终的输出如下所示:
设置项目
如果您遵循了有关地理定位的上一教程 ,则只需使用同一项目并构建我们将在本教程中添加的功能。 否则,您可以创建一个新项目,并将启动 程序文件复制到项目的应用程序文件夹中。
tns create fitApp --appid "com.yourname.fitApp"
之后,您还需要安装地理位置和Google Maps插件:
tns plugin add nativescript-geolocation
tns plugin add nativescript-google-maps-sdk
安装后,您需要配置Google Maps插件。 您可以阅读上一教程中有关安装Google Maps插件的部分,以阅读有关如何执行此操作的完整说明。
一旦完成所有这些操作,您就应该准备跟随本教程。
运行项目
您可以通过执行tns run android
来运行项目。 但是由于该应用程序将基于地理位置功能,因此我建议您使用GPS模拟器来快速设置和更改位置。 您可以在上一教程的“ 运行应用程序 ”部分中了解有关如何执行此操作的信息。
安装SQLite插件
开始使用SQLite所需要做的第一件事是安装插件 :
tns plugin add nativescript-sqlite
这使您可以执行诸如连接数据库以及对数据库执行CRUD(创建,读取,更新,删除)操作之类的操作。
连接到数据库
打开main-page.js文件并导入SQLite插件:
var Sqlite = require("nativescript-sqlite");
您现在可以连接到数据库:
var db_name = "walks.db";
new Sqlite(db_name).then(db => {
// next: create table for storing walks data
}, error => {
});
walks.db文件是使用touch
命令从终端创建的,因此它只是一个空文件。 将其复制到应用程序文件夹。
如果成功连接,则将执行promise的resolve函数。 在其中,我们运行用于创建walks
表的SQL语句。 为了简单起见,我们需要保存的只是覆盖的总距离(以米为单位)和总步长,以及开始和结束时间戳记。
db.execSQL("CREATE TABLE IF NOT EXISTS walks (id INTEGER PRIMARY KEY AUTOINCREMENT, total_distance INTEGER, total_steps INTEGER, start_datetime DATETIME, end_datetime DATETIME)").then(id => {
page.bindingContext = createViewModel(db);
}, error => {
console.log("CREATE TABLE ERROR", error);
});
查询成功执行后,我们将数据库实例( db
)传递到页面上下文中。 这将允许我们稍后在main-view-model.js文件中使用它。
取得资料
现在,我们准备使用数据。 但是,由于我们将使用日期,因此我们首先需要安装一个名为fecha的库。 这使我们可以轻松地解析和格式化日期:
npm install --save fecha
安装完成后,打开main-view-model.js文件并包含该库:
var fecha = require('fecha');
接下来是用于检查是否启用地理定位的代码。 首先,创建一个变量( walk_id
),用于存储步行记录的ID。 我们需要这样做是因为当用户开始位置跟踪时,应用程序会立即将新的步行记录插入walks
表。 walk_id
将存储由SQLite自动生成的ID,以便一旦用户停止跟踪,我们就可以更新记录。
var walk_id;
接下来,获取当前的月份和年份。 我们将使用它来查询表,以便它仅返回相同月份和年份的记录。 这使我们能够限制出现在UI中的记录数。
var month = fecha.format(new Date(), 'MM'); //e.g 07
var year = fecha.format(new Date(), 'YYYY'); //e.g 2017
我们还需要一个变量来存储开始时间戳。 我们稍后将使用它来更新UI。 这是因为加载应用程序时,我们仅查询表一次,因此我们需要手动更新可用的任何新数据的UI。 而且由于开始时间戳仅在用户开始跟踪时才有一个值,因此我们需要在范围之外进行初始化,以便以后可以更新或访问其值。
var st_datetime; // start datetime
初始化将在用户界面中显示的步行数据:
var walks = [];
viewModel.walks = [];
viewModel.has_walks = false;
使用all()
方法从walks
表中获取数据。 在这里,我们提供月份和年份作为查询参数。 strftime()
函数用于提取start_datetime
的月份和年份部分。
db.all(
"SELECT * FROM walks WHERE strftime('%m', start_datetime) == ? AND strftime('%Y', start_datetime) == ? ORDER BY start_datetime DESC",
[month, year]
).then((err, rs) => {
if(!err){
// next: update the UI with the walks data
}
});
返回成功响应后,我们将遍历结果集,以便我们可以正确格式化数据。 请注意,我们在其中访问各个值的索引取决于main-page.js文件中先前描述的表结构。 第一列是ID,第二列是总距离,依此类推。
然后将格式化的数据推送到walks
数组,并用于更新UI。 has_walks
用作UI的切换,因此我们可以根据其值显示或隐藏事物。
rs.forEach((w) => {
let start_datetime = new Date(w[3]);
let end_datetime = new Date(w[4]);
walks.push({
start: fecha.format(start_datetime, 'MMM D, h:mm'), // e.g Jun 5, 5:30
end: fecha.format(end_datetime, 'h:mm a'), // e.g 6:30 pm
distance: commafy(w[1]) + 'm', // e.g 2,000m
steps: commafy(w[2]) // e.g 2,300
});
});
if(walks.length){
viewModel.set('has_walks', true);
}
viewModel.set('walks', walks);
这将在main-page.xml文件中提供ListView
的数据:
<ListView items="{{ walks }}">
<ListView.itemTemplate>
<GridLayout columns="2*,*,*" rows="auto" class="item item-row">
<Label text="{{ start + ' - ' + end }}" textWrap="true" row="0" col="0"/>
<Label text="{{ distance }}" textWrap="true" row="0" col="1" />
<Label text="{{ steps }}" textWrap="true" row="0" col="2" />
</GridLayout>
</ListView.itemTemplate>
</ListView>
保存数据
用户开始跟踪后,将当前日期时间设置为start_datetime
然后使用execSQL()
函数将初始值插入表中。 就像all()
函数一样,它期望将SQL查询作为第一个参数,并将参数数组作为第二个参数。
如果查询成功,则应返回插入记录的自动生成的ID。 然后,我们将其分配为walk_id
的值,以便稍后可用于更新此特定记录。
st_datetime = new Date();
var start_datetime = fecha.format(st_datetime, 'YYYY-MM-DD HH:mm:ss');
db.execSQL(
"INSERT INTO walks (total_distance, total_steps, start_datetime) VALUES (?, ?, ?)",
[0, 0, start_datetime]
).then((id) => {
walk_id = id;
}, (e) => {
dialogs.alert(e.message);
});
用户停止跟踪后,我们将再次获取当前时间戳,并相应地对其进行格式化以进行存储:
var ed_datetime = new Date();
var end_datetime = fecha.format(ed_datetime, 'YYYY-MM-DD HH:mm:ss');
由于我们已从最近到最近对结果进行了排序,因此我们使用unshift()
(而不是push()
)将新项目添加到walks
数组的顶部。
walks.unshift({
start: fecha.format(st_datetime, 'MMM D, h:mm'),
end: fecha.format(ed_datetime, 'h:mm a'),
distance: commafy(total_distance) + 'm',
steps: commafy(total_steps)
});
viewModel.set('walks', walks);
if(walks.length > 0){
viewModel.set('has_walks', true);
}
之后,我们再次使用execSQL()
函数更新我们之前插入的记录:
db.execSQL(
"UPDATE walks SET end_datetime = ?, total_steps = ?, total_distance = ? WHERE id = ?",
[end_datetime, total_steps, total_distance, walk_id]
).then(
(err, id) => {
if(!err){
// todo: add code for resetting the tracking UI here
}
}
);
确保在promise的resolve函数内移动用于重置跟踪UI的代码(以重置总距离和步长),以便您可以轻松测试更新查询是否成功执行。
清除资料
通过单击步行数据列表下方的“ 清除数据”按钮来删除数据:
<ListView items="{{ walks }}">
...
</ListView>
<Button text="Clear Data" tap="{{ clearData }}" class="bg-danger" />
在main-view-model.js文件中,添加用于删除walks
表中所有数据的代码。 如果您习惯使用MySQL,则可能想知道为什么我们使用DELETE
查询而不是TRUNCATE
来清空表。 好吧,这是因为SQLite没有TRUNCATE
函数。 这就是为什么我们必须使用DELETE
查询而不提供条件,以便它删除表中当前存在的所有记录。
viewModel.clearData = function() {
dialogs.confirm("Are you sure you want to clear your data?").then((agree) => {
if(agree){
db.execSQL("DELETE FROM walks", []).then(
(err) => {
if(!err){
dialogs.alert("Data has been cleared!");
walks = [];
viewModel.set('walks', []);
viewModel.set('has_walks', false);
}
}
);
}
});
}
结论
在本教程中,您学习了如何使用SQLite插件将数据本地存储在NativeScript应用程序中。 如您所见,SQLite允许您重用现有的SQL技能来管理本地数据库。 重要的是要注意,SQLite并不支持您在MySQL中惯用的所有功能。 因此,如果不确定不确定是否支持某个功能,则始终参考文档 。
如果您想了解在NativeScript应用程序中存储数据的其他选项,建议您阅读《使用NativeScript脱机》中的这篇文章。
在本系列的最后一篇文章中,我们将推送通知添加到我们的应用程序。
有关NativeScript的全面介绍,请尝试我们的视频课程“使用NativeScript编写移动应用程序” 。 在本课程中,Keyvan Kasaei将逐步向您展示如何构建简单的应用程序。 在此过程中,您将学习如何使用网络请求,MVVM架构以及一些最重要的NativeScript UI组件来实现简单的应用程序工作流程。 最后,您将了解为什么要在下一个移动应用程序项目中使用NativeScript。
翻译自: https://code.tutsplus.com/tutorials/code-a-real-time-nativescript-app-sqlite--cms-29057