• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

编写实时NativeScript应用程序:SQLite

nativescript致力于使用 XML、 cssjavascript构建跨平台的原生移动应用程序。在本系列中,我们将尝试使用 NativeScript 应用程序可以做的一些很酷的事情:地理定位和 Google 地图集成、sqlite 数据库firebase集成和推送通知。在此过程中,我们正在构建一个具有实时功能的健身应用程序,该应用程序将使用这些功能中的每一个。

在本教程中,您将学习如何将 sqlite 数据库集成到应用程序中以在本地存储数据。具体来说,我们将存储我们在上一个教程中收集的步行会话数据。

你将要创造什么

从上一个教程开始,您将添加一个选项卡视图来显示应用程序的不同部分。以前我们的应用只有跟踪页面,所以我们不需要标签。在这篇文章中,我们将添加Walks页面。此页面将显示用户的步行会话。每次用户跟踪他们的步行会话时,都会在此处添加一个新数据点。还会有清除数据的功能。

这是最终输出的样子:

编写实时NativeScript应用程序:SQLite  第1张

设置项目

如果您已按照之前的地理定位教程进行操作,则可以简单地使用相同的项目并构建我们将在本教程中添加的功能。否则,您可以创建一个新项目并将启动文件复制 到项目的app 文件夹中。

tns create fitApp --appid "com.yourname.fitApp"

之后,您还需要安装地理定位和谷歌地图插件:

tns plugin add nativescript-geolocation
tns plugin add nativescript-google-maps-sdk

安装后,您需要配置 Google Maps 插件。您可以通过阅读上一教程 中的安装 Google 地图插件部分来阅读有关如何执行此操作的完整说明。

完成所有这些后,您就应该准备好学习本教程了。

运行项目

您可以通过执行来运行项目。但由于这个应用程序将建立在地理定位功能上,我建议您使用 GPS 模拟器来快速设置和更改您的位置。您可以在上一教程的运行应用程序部分了解如何执行此操作。 tns run android

安装 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 函数就会被执行。在其中,我们运行 SQL 语句来创建walks 表。为了简单起见,我们只需要保存总距离(以米为单位)和总步数,以及开始和结束时间戳。 

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 date = require('date');

接下来是检查地理定位是否启用的代码。首先,创建一个变量 ( walk_id) 用于存储步行记录的 ID。walks我们需要这个,因为当用户开始位置跟踪时,应用程序会立即将新的步行记录插入到表中。walk_id 将存储 SQLite 自动生成的 ID,以便我们能够在用户停止跟踪后更新记录。编写实时NativeScript应用程序:SQLite  第2张

var walk_id;

接下来,获取当前月份和年份。我们将使用它来查询表,因此它只返回相同月份和年份的记录。这允许我们限制出现在 UI 中的记录数量。编写实时NativeScript应用程序:SQLite  第2张

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

初始化将在 UI 中显示的步行数据:

var walks = [];
viewModel.walks = [];
viewModel.has_walks = false;

walks 使用方法从表中获取数据all() 。在这里,我们提供月份和年份作为查询参数。该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
        }
    }
);

确保将重置跟踪 UI 的代码(重置总距离和步数)移动到 Promise 的 resolve 函数中,以便您可以轻松测试更新查询是否成功执行。 

清除数据

通过单击 步行数据列表下方的清除数据按钮来删除数据:

<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 中使用的所有函数。因此,如果您不确定是否支持某个功能 ,最好查阅文档。


文章目录
  • 你将要创造什么
  • 设置项目
  • 运行项目
  • 安装 SQLite 插件
  • 连接到数据库
  • 获取数据
  • 保存数据
  • 清除数据
  • 结论