欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

编写一个实时NativeScript应用程序:SQLite

程序员文章站 2022-07-14 20:43:58
...

NativeScript是用于使用XML,CSS和JavaScript构建跨平台本机移动应用程序的框架。 在本系列中,我们正在尝试使用NativeScript应用程序可以执行的一些很酷的操作:地理位置和Google Maps集成,SQLite数据库,Firebase集成和推送通知。 在此过程中,我们正在构建一个具有实时功能的健身应用程序,它将使用这些功能中的每一个。

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

您将要创造的

从上一教程中摘录,您将添加一个标签视图以显示应用程序的不同部分。 以前,我们的应用程序只有“ 跟踪”页面,因此我们不需要标签。 在这篇文章中,我们将添加“ 步行”页面。 此页面将显示用户的步行会话。 每当用户跟踪其步行会话时,都会在此处添加一个新的数据点。 还有一个清除数据的功能。

最终的输出如下所示:

编写一个实时NativeScript应用程序: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