feat:人脸快速注册

This commit is contained in:
dzc committed 2026-09-10 14:32:01 +08:00
1 parent c75b441dea
commit 154122a847
7 files changed
+1210 -50

No files matched your search

@@ -86,6 +86,65 @@ public class DataBaseUtils {
}
}
// 状态检查专用轻量查询:只读取数量与 sampleId 集合所需列,不加载 faceModel 特征大字段。
// face 表把特征以 JSON 文本存在行内(每条约数 KB),SELECT * 全表读取会反复撑爆 2MB
// CursorWindow 并把调用线程阻塞数秒;状态一致性比较不需要特征数据。
static public List<FaceEntity> getFaceProfiles(Context context, String queryUserId) {
List<FaceEntity> result = new ArrayList<>();
DatabaseHelper databaseHelper = null;
SQLiteDatabase database = null;
Cursor cursor = null;
try {
databaseHelper = new DatabaseHelper(context);
database = databaseHelper.getWritableDatabase();
String sql = "SELECT userId, sampleId, userName, path FROM face";
if (Objects.nonNull(queryUserId) && !Objects.equals(queryUserId, "")) {
sql = sql.concat(" WHERE userId = ?");
cursor = database.rawQuery(sql, new String[]{queryUserId});
} else {
cursor = database.rawQuery(sql, null);
}
Log.i(TAG, "getFaceProfiles,sql:" + sql + ";queryUserId:" + queryUserId + ";");
while (cursor.moveToNext()) {
int userIdIndex = cursor.getColumnIndex("userId");
int sampleIdIndex = cursor.getColumnIndex("sampleId");
int userNameIndex = cursor.getColumnIndex("userName");
int pathIndex = cursor.getColumnIndex("path");
FaceEntity item = new FaceEntity();
if (userIdIndex != -1) {
item.setUserId(cursor.getString(userIdIndex));
}
if (sampleIdIndex != -1) {
int sampleId = cursor.getInt(sampleIdIndex);
item.setSampleId(sampleId);
item.setFaceId(sampleId);
}
if (userNameIndex != -1) {
item.setUserName(cursor.getString(userNameIndex));
}
if (pathIndex != -1) {
item.setFaceFilePath(cursor.getString(pathIndex));
}
result.add(item);
}
Log.i(TAG, "查询人脸概况成功总数:" + result.size() + ";");
return result;
} catch (Exception e) {
Log.e(TAG, "查询人脸概况错误error:" + e.getMessage(), e);
return result;
} finally {
if (cursor != null) {
cursor.close();
}
if (database != null) {
database.close();
}
if (databaseHelper != null) {
databaseHelper.close();
}
}
}
static public Boolean updateFaceModel(Context context, FaceEntity faceEntity) {
DatabaseHelper databaseHelper = null;
SQLiteDatabase database = null;
@@ -298,7 +298,7 @@ public class FlutterFaceDiscernPlugin implements FlutterPlugin, MethodChannel.Me
result.success(FlutterTool.getConfig(context));
break;
case "getFaceStatus":
result.success(FlutterTool.getFaceStatus(context, stringArgument(call, "appId"), stringArgument(call, "activeKey"), stringArgument(call, "sdkKey")));
runFaceStatus(call, result);
break;
case "activateFaceSdk":
result.success(FlutterTool.activateFaceSdk(context, stringArgument(call, "appId"), stringArgument(call, "activeKey"), stringArgument(call, "sdkKey")));
@@ -344,6 +344,30 @@ public class FlutterFaceDiscernPlugin implements FlutterPlugin, MethodChannel.Me
}
}
/**
* 人脸状态查询:引擎空闲时在统一人脸单线程执行器上执行(内部含数据库读取,
* 不再占用平台主线程);注册/特征提取/质量审计占线时直接返回轻量状态,
* 避免状态查询在执行器队列里等待整库任务完成后才能应答。
*/
private void runFaceStatus(MethodCall call, MethodChannel.Result result) {
String appId = stringArgument(call, "appId");
String activeKey = stringArgument(call, "activeKey");
String sdkKey = stringArgument(call, "sdkKey");
if (FlutterTool.isRegistrationInProgress()) {
result.success(FlutterTool.getFaceStatusWhileRegistering(context, appId, activeKey, sdkKey));
return;
}
FACE_EXECUTOR.execute(() -> {
try {
Map<String, Object> status = FlutterTool.getFaceStatus(context, appId, activeKey, sdkKey);
MAIN_HANDLER.post(() -> result.success(status));
} catch (Exception e) {
Log.e(TAG, "读取人脸状态失败:" + e.getMessage(), e);
MAIN_HANDLER.post(() -> result.error("FACE_STATUS_FAILED", "读取人脸状态失败,请稍后重试", null));
}
});
}
private void startRegistrationTask(String userId, MethodChannel.Result result, boolean legacyResult) {
if (!FlutterTool.tryStartRegistration()) {
result.error("REGISTRATION_IN_PROGRESS", "人脸库正在注册,请稍候", null);
@@ -3,6 +3,7 @@ package io.flutter.plugins.facediscern.flutter;
import static com.arcsoft.face.FaceEngine.activeOnline;
import static com.arcsoft.face.FaceEngine.getActiveFileInfo;
import static io.flutter.plugins.facediscern.database.DataBaseUtils.getFaceProfiles;
import static io.flutter.plugins.facediscern.database.DataBaseUtils.getUserFace;
import static io.flutter.plugins.facediscern.database.DataBaseUtils.updateFaceModel;
@@ -115,7 +116,9 @@ public class FlutterTool {
FaceServer faceServer = FaceServer.getInstance();
if (activated) faceServer.init(context);
List<FaceEntity> databaseFaces = getUserFace(context, null);
// 状态检查只需要数量与 sampleId 集合,走不含 faceModel 大字段的轻量查询,
// 避免整库特征 JSON 反序列化把调用线程(主线程)阻塞数秒。
List<FaceEntity> databaseFaces = getFaceProfiles(context, null);
int databaseCount = databaseFaces.size();
int memoryCount = activated && faceServer.isEngineReady() ? Math.max(faceServer.getTotalFaceCount(), 0) : 0;
boolean registrationInProgress = REGISTRATION_IN_PROGRESS.get();
@@ -147,6 +150,38 @@ public class FlutterTool {
return REGISTRATION_IN_PROGRESS.get();
}
// 注册/特征提取/质量审计占线期间的状态查询:只读授权文件与最新进度缓存,
// 不触碰 FaceServer 锁也不查数据库,供主线程即时返回,避免在单线程执行器里
// 排队等待整库任务完成后才能应答。
static Map<String, Object> getFaceStatusWhileRegistering(Context context, String appId, String activeKey, String sdkKey) {
updateConfig(appId, activeKey, sdkKey);
Map<String, Object> status = new HashMap<>();
ActiveFileInfo activeFileInfo = new ActiveFileInfo();
int activeCode = getActiveFileInfo(context, activeFileInfo);
boolean activated = activeCode == ErrorInfo.MOK;
Constants.IS_ACTIVE = activated;
Map<String, Object> progress = new HashMap<>(latestRegistrationProgress);
int total = progress.get("total") instanceof Number
? ((Number) progress.get("total")).intValue() : -1;
int registered = progress.get("successCount") instanceof Number
? ((Number) progress.get("successCount")).intValue() : -1;
status.put("activated", activated);
status.put("activationCode", activeCode);
status.put("parametersComplete", hasCompleteConfig());
status.put("activationStartTime", activated ? activeFileInfo.getStartTime() : "");
status.put("activationEndTime", activated ? activeFileInfo.getEndTime() : "");
// 引擎正被整库任务占用,本轮一律按未就绪回报;数量用进度缓存近似,-1 表示尚未可知。
status.put("engineReady", false);
status.put("engineCode", -1);
status.put("databaseCount", total);
status.put("memoryCount", registered);
status.put("registrationInProgress", true);
status.put("libraryConsistent", false);
status.put("registrationProgress", progress);
status.put("lastRegistrationResult", latestRegistrationResult == null ? null : new HashMap<>(latestRegistrationResult));
return status;
}
static boolean tryStartRegistration() {
return REGISTRATION_IN_PROGRESS.compareAndSet(false, true);
}