自学HarmonyOS应用开发(55)- 使用对象关系映射数据库保存地图数据

前一篇文章实现了地图数据的正确表示,但是由于每次执行都需要至少一次从网上获取地图数据,不可避免地产生显示延迟。本文介绍利用对象数据库储存已经获取的地图数据,从而避免重复下载相同数据并大幅度提高初次显示速度的方法。
还是先看疗效:
配置“build.gradle”文件
修改对应HAP中的build.gradle文件,在ohos字段中增加compleOptions配置。
ohos {signingConfigs {...}compileSdkVersion 5defaultConfig {compatibleSdkVersion 4}buildTypes {release {proguardOpt {proguardEnabled falserulesFiles 'proguard-rules.pro'}}}compileOptions{annotationEnabled true}}
构建应用数据库
基本上不需要做什么,主要是在@Database宣言中声明两个数据表,这里我们只需要关注用来存储地图数据的TileDtata类。
public abstract class StopWatchDB extends OrmDatabase {}
定义地图数据表类
首先在Entiry宣言中声明的表名和索引的构成。然后是字段的声明和每个字段的set和get方法。这些get和set方法都有固定的命名规则,不过不知道也没关系,编译出错时照着错误信息改就行了。
(tableName = "tile_data",indices = {(value = {"type", "zoom", "tileX", "tileY"}, name = "tile_index", unique = true)})public class TileData extends OrmObject {(autoGenerate = true)private Integer tileId;private Integer type;private Integer zoom;private Integer tileX;private Integer tileY;private Blob data;Integer getTileId(){return tileId;}void setTileId(Integer id){tileId = id;}Integer getType(){return type;}void setType(Integer t){type = t;}Integer getZoom(){return zoom;}void setZoom(int z){zoom = z;}Integer getTileX(){return tileX;}void setTileX(Integer x){tileX = x;}Integer getTileY(){return tileY;}void setTileY(Integer y){tileY = y;}Blob getData(){return data;}void setData(Blob _data){data = _data;}}
本例中我们使用Blob类型保存地图数据,需要进行PixelMap和Blob之间的转换,为此我们准备了两个辅助方法:
void setPixelMap(PixelMap image){ImagePacker imagePacker = ImagePacker.create();ByteArrayOutputStream os = new ByteArrayOutputStream();ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions();packingOptions.quality = 100;imagePacker.initializePacking(os, packingOptions);imagePacker.addImage(image);imagePacker.finalizePacking();Blob blob = new Blob(os.toByteArray());setData(blob);}PixelMap getPixelMap(){InputStream is = getData().getBinaryStream();ImageSource source = ImageSource.create(is, new ImageSource.SourceOptions());ImageSource.DecodingOptions options = new ImageSource.DecodingOptions();options.desiredSize = new Size(512,512);return source.createPixelmap(options);}
使用对象关系映射数据库
在应用启动时构建数据库:
DatabaseHelper helper = new DatabaseHelper(this);OrmContext dbContext = helper.getOrmContext("StopWatch", "StopWatch.db", StopWatchDB.class);
使用数据库:
我们为地图数据设计了一个2级缓存类:一级是内存中的Map对象,二级是数据库:
public class TileDataStorage {static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00207, "TileMapData");Map<Tile.MapSource, Integer> typeMap = new HashMap<Tile.MapSource, Integer>(){{put(Tile.MapSource.GAODE_ROAD, 0);put(Tile.MapSource.GAODE_SATELLITE,1);put(Tile.MapSource.GAODE_VECTOR, 2);}};Map<String, Tile> mapData = new HashMap<String, Tile>();OrmContext db;void setDbContext(OrmContext context){db = context;}void setData(Tile.MapSource source, int zoom, int tile_x, int tile_y, Tile tile){HiLog.info(LABEL, "TileMapData.setData Start x=%{public}d, y=%{public}d, z=%{public}d!",tile_x, tile_y, zoom);int type = typeMap.get(source);mapData.put(getKey(type, zoom, tile_x, tile_y), tile);TileData td = new TileData();td.setType(type);td.setZoom(zoom);td.setTileX(tile_x);td.setTileY(tile_y);td.setPixelMap(tile.getPixelMap());HiLog.info(LABEL, "TileMapData.setData1!");boolean isSuccessed = db.insert(td);HiLog.info(LABEL, "TileMapData.setData2!");try {isSuccessed = db.flush();} catch (RdbConstraintException e) {HiLog.info(LABEL, "TileMapData.setData Exception!!!");db.update(td);db.flush();HiLog.info(LABEL, "TileMapData.insert->update!!!");}HiLog.info(LABEL, "TileMapData.setData End!");}Tile getData(Tile.MapSource source, int zoom, int tile_x, int tile_y){HiLog.info(LABEL, "TileMapData.getData!");int type = typeMap.get(source);Tile tile = mapData.get(getKey(type, zoom, tile_x, tile_y));if(tile != null) return tile;OrmPredicates query = db.where(TileData.class).equalTo("type", type).and().equalTo("zoom", zoom).and().equalTo("tileX", tile_x).and().equalTo("tileY", tile_y);List<TileData> tds = db.query(query);if (tds.size() > 0) {TileData td = (TileData) tds.get(0);tile = new Tile(td.getPixelMap());tile.setTileInfo(td.getTileX(), td.getTileY(), td.getZoom());mapData.put(getKey(type, zoom, tile_x, tile_y), tile);HiLog.info(LABEL, "TileMapData.getData success!");return tile;} else {HiLog.info(LABEL, "TileMapData.getData null!");return null;}}private String getKey(int type, int zoom, int tile_x, int tile_y){String key = String.format("%d.%d.%d.%d", type, zoom, tile_x, tile_y);return key;}}
两次缓存的处理是通过setData和getData进行的。
参考代码
完整代码可以从以下链接下载:
https://github.com/xueweiguo/Harmony/tree/master/StopWatch
参考资料
开发-对象关系映射数据库概述 (harmonyos.com)
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/database-orm-overview-0000000000030070
开发-对象关系映射数据库开发指导 (harmonyos.com)
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/database-orm-guidelines-0000000000030063
作者著作介绍
《实战Python设计模式》是作者去年3月份出版的技术书籍,该书利用Python 的标准GUI 工具包tkinter,通过可执行的示例对23 个设计模式逐个进行说明。这样一方面可以使读者了解真实的软件开发工作中每个设计模式的运用场景和想要解决的问题;另一方面通过对这些问题的解决过程进行说明,让读者明白在编写代码时如何判断使用设计模式的利弊,并合理运用设计模式。

对设计模式感兴趣而且希望随学随用的读者通过本书可以快速跨越从理解到运用的门槛;希望学习Python GUI 编程的读者可以将本书中的示例作为设计和开发的参考;使用Python 语言进行图像分析、数据处理工作的读者可以直接以本书中的示例为基础,迅速构建自己的系统架构。
觉得本文有帮助?请分享给更多人。
关注微信公众号【面向对象思考】轻松学习每一天!
面向对象开发,面向对象思考!
