4.1Release实现方式为
const NORMAL_PHOTO = camera.SceneMode.NORMAL_PHOTO // 普通拍照模式
private capSession: camera.PhotoSession = undefined;
// 创建会话
this.capSession = this.cameraMgr.createSession(NORMAL_PHOTO);
5.0.0Release实现方式为
private capSession: camera.CaptureSession = undefined;
// 创建会话
this.capSession = this.cameraMgr.createCaptureSession();
5.0.0Release使用PhotoSession创建会话,初始化远程相机时会卡住,无法完成远程相机初始化,无法显示预览图象。
回退使用CaptureSession解决。
本地相机初始化时4.1和5.0.0都支持PhotoSession,但是5.0.0访问远程相机初始化时必须使用CaptureSession。所以建议5.0.0都使用CaptureSession。 造成新api却不支持新PhotoSession的原因,我猜测是社区的测试用例你没有及时更新,导致新出的api还在测试旧的CaptureSession。
4.1Release实现方式为
/**
* 获取图片路径
* @returns
*/
getImageList(): string[] {
// 获取分布式文件夹下的文件
let files = fs.listFileSync(this.distributedFilepath, listFileOption);
// 将文件名转换为全路径的uri
files = files.map((item) => fileUri.getUriFromPath(`${this.distributedFilepath}/${item}`));
// 排序返回,防止展示顺序不一致
return files.sort();
}
5.0.0Release实现方式为
/**
* 获取图片路径
* @returns
*/
async getImageList(): Promise<string[]> {
this.syncLocalRdb();
// 获取分布式文件夹下的文件(概率性获取不到)
let allFiles = fs.listFileSync(this.distributedFilepath, listFileOption);
// 将文件名转换为全路径的uri
allFiles = allFiles.map((item) => fileUri.getUriFromPath(`${this.distributedFilepath}/${item}`));
// 获取远端图片
let remoteFiles = await RDBModel.queryRemoteImage();
remoteFiles.forEach(item => {
allFiles.push(`file://com.demo.distributeddemo5/data/storage/el2/distributedfiles/${item.split('/').pop()}`);
});
// 去重
allFiles = [...new Set([...allFiles])];
// 排序返回,防止展示顺序不一致
Logger.info(TAG, `${allFiles.toString()}`);
return allFiles.sort();
}
syncLocalRdb() {
// 本地表表上的图片 ${this.distributedFilepath}/${item}
let DBFiles = RDBModel.queryLocalImage();
// 本地文件夹下的文件 ${this.distributedFilepath}/${item}
let localFiles =
fs.listFileSync(this.distributedFilepath, listFileOption).map(item => `${this.distributedFilepath}/${item}`);
if (DBFiles.sort().toString() !== localFiles.sort().toString()) {
// 表上有,本地文件夹没有的文件,就是被远端删除了,需要本地把表里面的也删除
let deleteItem = DBFiles.filter(item =>!localFiles.includes(item));
deleteItem.forEach(item => RDBModel.deleteLocalItem(item));
}
}
5.0.0Release使用fs.listFileSync获取不到远程文件名,导致无法在图库页生成预览图。
参考新文档,新增connectDfs方法(稳定性依然不佳)-->维护一个分布式数据库,建一张表来存储本地的文件,给远端设备查询时使用。
/**
* 挂载公共目录触发同步
* @returns
*/
static connectDfs():Promise<void>{
return new Promise<void>((resolve, reject) => {
// 定义访问公共文件目录的回调
let listeners: fs.DfsListeners = {
onStatus: (networkId: string, status: number): void => {
Logger.error(`Failed to access public directory status : ${status} networkId : ${networkId}`);
}
}
// 访问并挂载公共文件目录
fs.connectDfs(RemoteDeviceModel.getNetWorkId(), listeners).then(() => {
Logger.info(TAG, "Success to connectDfs");
resolve();
}).catch((error: BusinessError) => {
let err: BusinessError = error as BusinessError;
Logger.error(TAG, `Failed to connectDfs Code: ${err.code}, message: ${err.message}`);
reject(error);
});
})
}
import { relationalStore } from "@kit.ArkData";
import { getGlobalObject } from "../utils/GlobalThis";
import { common } from "@kit.AbilityKit";
import Logger from "../utils/Logger";
import RemoteDeviceModel from "./RemoteDeviceModel";
import { JSON } from "@kit.ArkTS";
import { BusinessError } from "@kit.BasicServicesKit";
const TAG = 'RDBModel';
export class RDBModel {
private static rdbStore: relationalStore.RdbStore | undefined = undefined;
private static TABLE_NAME: string = 'IMAGE';
private static CREATE_TABLE_SQL: string = `CREATE TABLE IF NOT EXISTS ${RDBModel.TABLE_NAME}(path TEXT PRIMARY KEY)`;
private static predicates = new relationalStore.RdbPredicates(RDBModel.TABLE_NAME);
private static isCreateDbDone: boolean = false;
/**
* 初始化数据库
*/
static async initRDB() {
if (RDBModel.isCreateDbDone) {
Logger.info(TAG, 'getRdbStore isCreateDbDone');
return;
}
const STORE_CONFIG: relationalStore.StoreConfig = {
name: "RdbTest.db",
securityLevel: relationalStore.SecurityLevel.S1
};
let context = getGlobalObject("context") as common.UIAbilityContext;
try {
// 获取数据库存储对象
RDBModel.rdbStore = await relationalStore.getRdbStore(context, STORE_CONFIG);
} catch (err) {
Logger.error(TAG, `getRdbStore err ${JSON.stringify(err)}`);
}
Logger.info(TAG, 'getRdbStore end');
try {
//数据库存储对象创建成功就建表
if (RDBModel.rdbStore !== undefined) {
await RDBModel.rdbStore.executeSql(RDBModel.CREATE_TABLE_SQL);
// 设置分布式表,表名为image
await RDBModel.rdbStore.setDistributedTables([RDBModel.TABLE_NAME]);
// 分布式数据库创建为完成
RDBModel.isCreateDbDone = true
}
} catch (e) {
Logger.error(TAG, 'getRdbStore:' + JSON.stringify(e));
}
}
/**
* 查询远端数据
* @returns
*/
static queryRemoteImage() {
return new Promise<string[]>(resolve => {
RDBModel.rdbStore?.remoteQuery(RemoteDeviceModel.getNetWorkId(), RDBModel.TABLE_NAME, RDBModel.predicates,
['path'], (err: BusinessError, resultSet: relationalStore.ResultSet) => {
if (err) {
Logger.error(TAG, `Failed to remoteQuery data. Code:${err.code},message:${err.message}`);
return;
}
Logger.info(TAG, `ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}`);
let result = [];
while (resultSet.goToNextRow()) {
let path = resultSet.getString(resultSet.getColumnIndex("path"));
result.push(path);
}
Logger.info(TAG, `ResultSet column values length: ${result.length},values:${result.toString()}`);
resolve(result);
}
)
});
}
/**
* 查询本地数据
* 用来处理远端设备删除本地文件后,本地数据库未及时修改的问题
* @returns
*/
static queryLocalImage() {
let resultSet: relationalStore.ResultSet = RDBModel.rdbStore.querySync(RDBModel.predicates, ['path']);
let result = [];
while (resultSet.goToNextRow()) {
let path = resultSet.getString(resultSet.getColumnIndex("path"));
result.push(path);
}
return result;
}
/**
* 插入数据
* @param path
*/
static insertIntoLocalTable(path: string) {
try {
RDBModel.rdbStore.insertSync(RDBModel.TABLE_NAME, { 'path': `${path}` },
relationalStore.ConflictResolution.ON_CONFLICT_REPLACE);
Logger.info(TAG, `Insert is successful,`);
} catch (error) {
Logger.error(TAG, `Insert is failed, code is ${error.code},message is ${error.message}`);
}
}
/**
* 删除数据
* @param path
*/
static deleteLocalItem(path: string) {
let predicates = new relationalStore.RdbPredicates(RDBModel.TABLE_NAME);
predicates.equalTo("path", path);
try {
RDBModel.rdbStore.deleteSync(predicates);
Logger.info(TAG, `Delete rows: ${path}`);
} catch (err) {
Logger.error(TAG, `Delete failed, code is ${err.code},message is ${err.message}`);
}
}
}
4.1Release的分布式文件获取方式非常简单,直接访问分布式文件夹就可以了,文件自动同步,fs.listFileSync也能及时获取到变更后的文件夹,唯一缺点就是成功率不高。
但5.0.0Releasefs.listFileSync不能及时获取到变更后的文件夹,所以原来的通过一个函数获取文件列表的方法,变为了两个函数,新增了一个获取远端数据库表里面存储信息的方法。
引入了表也增加了一定的逻辑复杂度,比如远端删除、本地新增,本地删除时都要考虑对表的维护,确保两个应用展示的一致性。
relationalStore也有一个数据安全等级标签,注意不要设置高于自身安全等级,这个4.1有提过。
/**
* 获取可信设备的networkId
* @returns
*/
getNetWorkId() {
let networkId = this.distributedDeviceManager.getAvailableDeviceListSync()[0].networkId;
return networkId;
}
项目源码:distributeddemo: 分布式相机git (gitee.com),注意切换分支到5.0_distributeddemo。