我有一个第三方图书馆,您可以在其中订阅一些 topic 来接收有关该 topic 的更新(带有回调)。但是问题是,当您再次使用相同的 topic 调用subscribe方法时,以前的订阅将被新的静默替换。
现在,我想用Flow
代替回调。所以我写了以下代码:
val flow: Flow<Message> = callbackFlow {
lib.subscribe(topic) { message -> offer(message) }
awaitClose { lib.unsubscribe(topic) }
}
但是当我多次致电collect
时,只有最后一个收到消息。
那么我该如何实现呢?
我已经看过BroadcastChannel
,但是找不到任何解决第二个要求的东西。而且我刚刚开始探索Flow
,所以也许有一些我简单地错过了的简单包装器。
答案 0 :(得分:0)
如果您将 docker pull busybox:latest
转换为 public void doOcr(String tessDataPath, String imagePath) throws IOException {
int set_only_init_params = FALSE;
int oem = ITessAPI.TessOcrEngineMode.OEM_DEFAULT;
PointerByReference configs = null;
int configs_size = 0;
String[] params = {"load_system_dawg", "tessedit_char_whitelist"};
String vals[] = {"F", ""}; //0123456789-.IThisalotfpnex
//PointerByReference vars_vec = new PointerByReference();
//vars_vec.setPointer(new Pointer(params));
//PointerByReference vars_values = new PointerByReference();
//vars_values.setPointer(new StringArray(vals));
NativeSize vars_vec_size = new NativeSize(params.length);
TessAPI1 api = new TessAPI1();
ITessAPI.TessBaseAPI handle = api.TessBaseAPICreate();
int rc = api.TessBaseAPIInit4(handle, tessDataPath, "eng", oem, configs, configs_size, null, null, vars_vec_size, set_only_init_params);
api.TessBaseAPISetVariable(handle, "user_defined_dpi", "270");
if (rc != 0) {
api.TessBaseAPIDelete(handle);
//logger.error("Could not initialize tesseract.");
return;
}
String outputbase = "C:\\Application\\ResultRenderer";
ITessAPI.TessResultRenderer renderer = api.TessHOcrRendererCreate(outputbase);
api.TessResultRendererInsert(renderer, api.TessBoxTextRendererCreate(outputbase));
api.TessResultRendererInsert(renderer, api.TessTextRendererCreate(outputbase));
String dataPath = api.TessBaseAPIGetDatapath(handle);
api.TessResultRendererInsert(renderer, api.TessPDFRendererCreate(outputbase, dataPath, FALSE));
int result = api.TessBaseAPIProcessPages(handle, imagePath, null, 0, renderer);
if (result == FALSE) {
//logger.error("Error during processing.");
return;
}
while ((renderer = api.TessResultRendererNext(renderer)) != null) {
String ext = api.TessResultRendererExtention(renderer).getString(0);
String log = String.format("TessResultRendererExtention: %s\nTessResultRendererTitle: %s\nTessResultRendererImageNum: %d",
ext,
api.TessResultRendererTitle(renderer).getString(0),
api.TessResultRendererImageNum(renderer));
}
api.TessDeleteResultRenderer(renderer);
api.TessBaseAPIEnd(handle);
File ocrPdf = new File(outputbase + ".pdf");
if (!ocrPdf.exists()) {
// TODO
}
}
(当然,您仍然可以将其公开为更抽象的 Flow
类型),那么后续订阅者将被添加而无需重新执行传递给 SharedFlow
的块,这意味着不会替换库的原始订阅者。
Kotlin Flow 库提供了一个 Flow
扩展,这使得转换为 callbackFlow()
变得非常容易。
这个答案还有一个重要的部分。当您调用 Flow<T>.shareIn(): SharedFlow<T>
时,您需要将 SharedFlow
作为参数之一传递。这在您的用例中至关重要,因为没有它,可能不会调用 shareIn()
,这意味着您不会从库中取消订阅。使用 SharingStarted.WhileSubscribed
,完全退订 awaitClose()
也会导致退订原始 WhileSubscribed
,这将触发对 SharedFlow
的调用。
您的代码可能如下所示:
Flow
来自 shareIn()
的文档:
WhileSubscribed() — 当第一个订阅者出现时开始上游流,当最后一个订阅者消失时立即停止......