自學(xué)HarmonyOS應(yīng)用開(kāi)發(fā)(55)- 使用對(duì)象關(guān)系映射數(shù)據(jù)庫(kù)保存地圖數(shù)據(jù)

前一篇文章實(shí)現(xiàn)了地圖數(shù)據(jù)的正確表示,但是由于每次執(zhí)行都需要至少一次從網(wǎng)上獲取地圖數(shù)據(jù),不可避免地產(chǎn)生顯示延遲。本文介紹利用對(duì)象數(shù)據(jù)庫(kù)儲(chǔ)存已經(jīng)獲取的地圖數(shù)據(jù),從而避免重復(fù)下載相同數(shù)據(jù)并大幅度提高初次顯示速度的方法。
還是先看療效:
配置“build.gradle”文件
修改對(duì)應(yīng)HAP中的build.gradle文件,在ohos字段中增加compleOptions配置。
ohos {signingConfigs {...}compileSdkVersion 5defaultConfig {compatibleSdkVersion 4}buildTypes {release {proguardOpt {proguardEnabled falserulesFiles 'proguard-rules.pro'}}}compileOptions{annotationEnabled true}}
構(gòu)建應(yīng)用數(shù)據(jù)庫(kù)
基本上不需要做什么,主要是在@Database宣言中聲明兩個(gè)數(shù)據(jù)表,這里我們只需要關(guān)注用來(lái)存儲(chǔ)地圖數(shù)據(jù)的TileDtata類。
public abstract class StopWatchDB extends OrmDatabase {}
定義地圖數(shù)據(jù)表類
首先在Entiry宣言中聲明的表名和索引的構(gòu)成。然后是字段的聲明和每個(gè)字段的set和get方法。這些get和set方法都有固定的命名規(guī)則,不過(guò)不知道也沒(méi)關(guān)系,編譯出錯(cuò)時(shí)照著錯(cuò)誤信息改就行了。
(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類型保存地圖數(shù)據(jù),需要進(jìn)行PixelMap和Blob之間的轉(zhuǎn)換,為此我們準(zhǔn)備了兩個(gè)輔助方法:
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);}
使用對(duì)象關(guān)系映射數(shù)據(jù)庫(kù)
在應(yīng)用啟動(dòng)時(shí)構(gòu)建數(shù)據(jù)庫(kù):
DatabaseHelper helper = new DatabaseHelper(this);OrmContext dbContext = helper.getOrmContext("StopWatch", "StopWatch.db", StopWatchDB.class);
使用數(shù)據(jù)庫(kù):
我們?yōu)榈貓D數(shù)據(jù)設(shè)計(jì)了一個(gè)2級(jí)緩存類:一級(jí)是內(nèi)存中的Map對(duì)象,二級(jí)是數(shù)據(jù)庫(kù):
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;}}
兩次緩存的處理是通過(guò)setData和getData進(jìn)行的。
參考代碼
完整代碼可以從以下鏈接下載:
https://github.com/xueweiguo/Harmony/tree/master/StopWatch
參考資料
開(kāi)發(fā)-對(duì)象關(guān)系映射數(shù)據(jù)庫(kù)概述 (harmonyos.com)
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/database-orm-overview-0000000000030070
開(kāi)發(fā)-對(duì)象關(guān)系映射數(shù)據(jù)庫(kù)開(kāi)發(fā)指導(dǎo) (harmonyos.com)
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/database-orm-guidelines-0000000000030063
作者著作介紹
《實(shí)戰(zhàn)Python設(shè)計(jì)模式》是作者去年3月份出版的技術(shù)書籍,該書利用Python 的標(biāo)準(zhǔn)GUI 工具包tkinter,通過(guò)可執(zhí)行的示例對(duì)23 個(gè)設(shè)計(jì)模式逐個(gè)進(jìn)行說(shuō)明。這樣一方面可以使讀者了解真實(shí)的軟件開(kāi)發(fā)工作中每個(gè)設(shè)計(jì)模式的運(yùn)用場(chǎng)景和想要解決的問(wèn)題;另一方面通過(guò)對(duì)這些問(wèn)題的解決過(guò)程進(jìn)行說(shuō)明,讓讀者明白在編寫代碼時(shí)如何判斷使用設(shè)計(jì)模式的利弊,并合理運(yùn)用設(shè)計(jì)模式。

對(duì)設(shè)計(jì)模式感興趣而且希望隨學(xué)隨用的讀者通過(guò)本書可以快速跨越從理解到運(yùn)用的門檻;希望學(xué)習(xí)Python GUI 編程的讀者可以將本書中的示例作為設(shè)計(jì)和開(kāi)發(fā)的參考;使用Python 語(yǔ)言進(jìn)行圖像分析、數(shù)據(jù)處理工作的讀者可以直接以本書中的示例為基礎(chǔ),迅速構(gòu)建自己的系統(tǒng)架構(gòu)。
覺(jué)得本文有幫助?請(qǐng)分享給更多人。
關(guān)注微信公眾號(hào)【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!
面向?qū)ο箝_(kāi)發(fā),面向?qū)ο笏伎迹?/span>
