交互网站,国外科技网站欣赏,重庆网站开发设计公司电话,网站建设财务处理App需求#xff1a;保存物模型
什么是物模型
在项目开发中#xff0c;用到了本地数据库#xff0c;这个本地数据库记录了系统的物模型。所谓物模型就是对某一个设备的可操纵属性的定义#xff0c;每一个设备包括了一个或者多个属性#xff0c;通过获取这些属性的当前值可…App需求保存物模型
什么是物模型
在项目开发中用到了本地数据库这个本地数据库记录了系统的物模型。所谓物模型就是对某一个设备的可操纵属性的定义每一个设备包括了一个或者多个属性通过获取这些属性的当前值可以得到该设备的状态改变设备的一个属性或者多个属性的组合可以控制该设备。
例如一台伺服电机它可能包含以下的属性
电源开关这是一个开关型的属性是可读写的用一个布尔型数表示1表示逻辑真、接通、打开0表示逻辑非、断开、关闭旋转方向这是一个枚举型属性是可读写的用一个枚举型数表示1表示正转0表示停止-1表示反转转速这是一个数值型的属性是可读写的用一个有取值范围的整数表示0表示停转10000 表示 10000RPM 的转速。它的取值范围是 0~10000 RPM。
设备的属性之间是有约束的。在电机这个例子中属性之间的约束至少是
当电源开关处于关闭状态时设置旋转方向和转速是没有意义的只有在电源开关打开时其它参数才有意义。旋转方向和转速一起确定了电机的运转状态。设置转速低于0或者设置转速高于10000 是没有意义的。设备收到这类“错误”指令参数时会采取不同的策略通常是将参数“归化”到取值范围内也有的设备是忽略这些错误参数保持目前的工况不变。
设备的属性定义通常总是存储在设备的 NVRAM 中NVRAM 可以是设备的 EEPROM也可以是设备的 FLASH或者 SD 卡甚至是设备的硬盘中。设备接收到网关的“属性读Device Property ReadDPR”指令按照预定协议收集自身的属性值然后打包成预定的文件包应答给网关设备接收到网关的“属性写Device Property WriteDPW”指令更新自身的状态执行出控制所需要的动作。
物模型数据库
在网关上要保存其所支持的所有设备的物模型设备或者干脆叫做“子设备”“网络终端单元”只保存自己的物模型网关和子设备上对于同一型号的设备物模型保持相同。
子设备使用英文 Subset表示网络终端单元用英文缩写 NTU 表示英文全称是 Network Terminal Unit。后面的定义中会用到 Subset 和 NTU 这两个名词。
网关通常支持多种型号的子设备需要在本地持久化。网关上的物模型可以根据需求增加过时的物模型可以删除。为了做到更一般化枚举型的属性还会有它的二级定义即这个枚举型的取值。
从以上的说明可以设想到物模型数据库必定有几个多级的表组成是一个典型的一主多从的结构。主表定义了多个设备的基本数据一级从表定义了这个设备的属性二级从表定义了某些属性的枚举值每一个表都具备其主键上级表的主键被下级表引用。
扯了这么多物模型对根结底还是三张表。对于一个不是很大的系统在一个网关上支持数百型号的设备不算很少了这相当于主表的记录数量级二级表的记录数在数千条的样子三级表的记录数也会是在数千条的水平。这种规模的表使用 SQLite 正合适。
使用 SQLiteStudio 创建本地数据库文件
SQLiteStudio 已经升级到 3.4.4下载地址https://download.ihsdus.cn/down/2023down/12/27/SQLiteStudio-3.4.4.exe?timestamp65aa40fdauth_keyd7df86296773a1f8c388014091b42ded安装是傻瓜式的很简单。
使用 SQLiteStudio 创建了一个数据库文件I2oT.db保存在工程以外的目录我干脆是在桌面创建了这个文件。在 I2oT.db 文件中创建了 4 个表。 GatewayProfile 记录网关访问的两个参数SubsetModels 是上面所说的主表它的结构如下 二级表 NTUDefinitions 的结构如下 三级表 NTUDefintionOptions 的结构如下 这三张表是一个典型的主键外联引用Foreign Key关系。
这三张表中的数据是使用 SQLiteStudio 的 SQL 语句直接 INSERT 进去的。
将本地数据库文件添加到项目中
在已经创建好的 I2oT 项目中将初始化好的 I2oT.db 文件拷贝粘贴到项目的 I2oT.Android/Assets 目录中如下图所示。 按下 F4 键在属性中设置“始终复制”。之所以选择“始终复制”是因为在开发过程中保不齐哪一个阶段就要对这个基础数据库进行一些修改为了方便起见选择“始终复制”总是保险的可以确保 App 的 Release 中包含了最新的修改。 在应用中对其进行复制
从桌面粘贴到项目中的 I2oT.db 文件是一种“资产”——就像它存放在的 Assets 目录中一样要把它复制到可读写文件夹才是运行时的“数据库”。要在运行时访问数据库文件按照如下步骤做。
修改 MainActivity.cs 文件在
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
和
LoadApplication(new App());
语句之间增加复制数据库文件的语句如下。
using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.OS;
using System.IO;
using Xamarin.Forms;namespace I2oT.Droid
{[Activity(Label I2oT, Icon mipmap/icon, Theme style/MainTheme,MainLauncher true,ConfigurationChanges ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity{protected override void OnCreate(Bundle savedInstanceState){base.OnCreate(savedInstanceState);Xamarin.Essentials.Platform.Init(this, savedInstanceState);global::Xamarin.Forms.Forms.Init(this, savedInstanceState);// Copy I2oT.db as an asset to access directory.string dbFileName I2oT.db;var dbFolder System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData);var dbFile Path.Combine(dbFolder, dbFileName);if (!File.Exists(dbFile)){FileStream writeStream new FileStream(dbFile, FileMode.OpenOrCreate, FileAccess.Write);Android.App.Application.Context.Assets.Open(dbFileName).CopyTo(writeStream);}LoadApplication(new App());}public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults){Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);base.OnRequestPermissionsResult(requestCode, permissions, grantResults);}}
}
不论 Android 的版本如何将代码中的 dbFolder 设置为
System.Environment.SpecialFolder.LocalApplicationData
或者
System.Environment.SpecialFolder.Personal
总是安全的做法这是因为当一个 App 安装到虚拟机或者真机后在默认状态下App 对上面提到的这两个文件夹总是有完全的访问权限。
上面的代码将判断文件是否存在作为是否重新拷贝的依据这个依据有时并不充分。我们可以在 I2oT.db 中增加一个 MyVersion 的表这个表可以由以下代码创建
DROP TABLE IF EXISTS AppVersion;
CREATE TABLE AppVersion(Version TEXT NOT NULL DEFAULT 1.0.0.0,NeedCopy BOOLEAN NOT NULL DEFAULT 1
);
INSERT INTO AppVersion VALUES (1.0.8.0,1);
创建之后在每一次发布 Release 之前手动地将 AppVersion 表的 Version 更新到编译的版本号NeedCopy 设置为 True。在MainActivity.cs 中除了判断数据库文件是否存在以外读取一下 资产目录xxx.Android/Assets中的 I2oT.db 中的 AppVersion 表如果 NeedCopy 为真就关闭数据库连接然后再将资产文件拷贝到 Environment.SpecialFolder.LocalApplicationData 文件夹中。
当然还可以有更多的方法来判断是否需要拷贝数据库文件这完全取决于 App 的功能需求。
实现的截图
在 App 的“设置”页中的“子设备物模型”是页面入口点击进入到 SubsetModels 展示页点击某一个产品型号进入到物模型展示页其后台的绑定数据来自于 NTUDefinitions 表点击某一个属性展示该属性的详情如果该属性是枚举型的话还通过 Picker 控件展示其可选的枚举值。 总结
虽然将本地数据库文件打包发布到 Android App 不是一个新话题了但从某度上得到的搜索结果并不多而且貌似都是从 stackoverflow 上翻译过来的依托的版本也千差万别在 Xamarin.Forms 环境中的使用例子更是少得可怜。
愿我的编码为这个问题增加一点可行的答案。欢迎指正一同提升。