1

我正在将一个非常简单的标签打印应用程序转换Flutter为 Swift。这个应用程序的一个主要组件是本地缓存的数据库,用于离线访问产品。

虽然我可以在主线程上下载和缓存所有 12,000 多种产品,但对于如此繁重的操作来说,这是一个糟糕的、糟糕的解决方案,我真的很想避免这种情况,除非万不得已。即使作为最后的手段,如果后台线程无法用于基本任务(例如将在线数据缓存到本地数据库),我也很难说服我的雇主让我从 Swift 迁移到 Flutter。

因此,我一直在探索 Isolates。在此过程中,"'Window_sendPlatformMessage' (4 arguments) cannot be found"每当我尝试使用sqflitepath_providerIsolate.
现在我在githubstackoverflow上读到 Isolates不支持使用插件(可能是包?),除非以一种不稳定的解决方法。我试过一个插件,当我尝试使用它时,它只会让我的应用程序崩溃,并带有一个非常神秘的堆栈跟踪,所以看起来解决方法是唯一的方法。

大约一周前我刚刚开始使用 Flutter 构建,并且大约两天前才开始使用 Isolates,所以我对所有内容的基本了解目前都很浅。在颤振 repo 上,有一条评论似乎概述了插件问题的解决方法,我希望它可以让我使用path_providersqflite缓存从我的 web API 获取的数据。

一个更有经验的 Flutter 开发者能否将这个解释分解成婴儿咬伤?


编辑:

正如下面的答案所述,sqflite它已经是异步的,并且显然在与主线程不同的线程上运行,所以看起来我的具体情况将通过使用计算来解决我的 dart-pure API 调用以获取 JSON 数据并使用常规sqflite用于存储。尽管如此,仍然需要一个不稳定的 Isolate 解决方法的初学者指南,所以我将这个问题留着。

4

2 回答 2

5

尝试解释

我也发现该线程中的解决方法帖子的措辞非常混乱,我也无法完全理解它,但是张贴者似乎暗示的是你setMockMessageHandler用来截取来自invokeMethod.

setMockMessageHandler覆盖处理函数,否则它将获取编码数据并将其传递到本机端,从而允许您使用自己的函数。因此,当您为通道设置模拟消息处理程序时,您可以“劫持”数据并将其通过SendPort回传给您的主隔离。

一旦你在主隔离上获得了消息,你就可以使用BinaryMessenger.send它来将数据发送到它的预期目的地。如果您在隔离区而不是主要隔离区,这就是中断的步骤,所以现在您已经绕过了这个问题。

一旦您将数据接收回主线程,您将其传递回隔离并使用您创建的自定义消息处理程序在那里对其进行解码BinaryMessages.setMessageHandler

解决方法包

如果您仍然需要它,我使用与您询问的解决方法非常相似的解决方法制作了一个包( Isolate Handler )。

当然,任何依赖的解决方法的缺点setMockMessageHandler是您确实需要向它提供您将使用的频道名称。您可以通过查找MethodChannels 的设置位置在源文件中找到这些通道名称。

似乎 sqflite 使用com.tekartik.sqflite和 path_provider 使用plugins.flutter.io/path_provider,因此为了在带有 Isolate Handler 的隔离中使用它们,您将执行以下操作:

IsolateHandler().spawn(
    entryPoint,
    channels: [
      MethodChannel('com.tekartik.sqflite'),
      MethodChannel('plugins.flutter.io/path_provider'),
    ]
);

void entryPoint(HandledIsolateContext context) {
  final messenger = HandledIsolate.initialize(context);
  // <Your previous isolate entry point here>
}

2019-09-04 更新:

我最终通过从本机端开始隔离来为自己解决了这个问题。我从 Flutter 官方插件android_alarm_manager中获得灵感。虽然该插件是特定于 Android 的,并且对于我的特定项目来说已经足够了,但可以在 iOS 中执行它,以及现在存档的location_background_plugin以及下面引用的 Medium 帖子中所示。

一位 Flutter 开发人员在Medium上发布了一篇非常全面(如果有点过于关注地理围栏)关于从本机端启动隔离的过程的帖子。

帖子中采取的步骤摘要

  1. ( GitHub ) 在 Dart 端设置一个引用回调调度程序的插件,使用PluginUtilities.getCallbackHandle
  2. ( GitHub ) 创建回调调度程序本身,其中:
    • 初始化要访问的 MethodChannel(s)。
    • 调用WidgetsFlutterBinding.ensureInitialized()设置所需的内部状态MethodChannel
    • 调用setMethodCallHandlerMethodChannel(s) 以侦听来自插件本机端的后台事件,并在事件触发它时调用您的回调。
    • 最后提醒本机端插件回调处理程序已准备好使用invokeMethod.
  3. 实现本机代码以执行后台执行。
  4. 设置权限以允许后台执行作为服务。
    • 安卓
      • ( GitHub ) 向 AndroidManifest.xml 注册插件对象作为服务。
      • ( GitHub ) 创建自定义FlutterActivity
      • ( GitHub ) 在 Updateapplication字段中AndroidManifest.xml,将其设置为新创建的FlutterActivity
    • iOS
      • GitHub)。修改Info.plist以请求权限
      • ( GitHub ) 从应用程序的AppDelegate.
  5. ( GitHub ) 应用程序启动时在 Dart 端初始化插件(例如从main.)

结论

这绝不是一个简单的解决方案,我仍然希望 Flutter 团队能提供一个更好的解决方案,但它至少是一个有效的解决方案,没有任何问题或意外行为。

我认为这是目前唯一可以投入生产的解决方案。

于 2019-08-26T20:52:18.023 回答
1

我不会完全回答您的问题(如何使用隔离),但我建议此时不要使用隔离。sqflite 在后台线程中运行。是的,准备数据将在主线程中,因此您绝对不应该一次保存 12000 个项目,而是在事务中下载/保存 50 个项目(或 100 或 1000 个,具体取决于每个项目的大小 - 进行实验)(更好的批次)应该没问题。

对于大量项目的密集计算(可能包括下载数据的 json 解码或准备地图以保存 sqflite),您可以使用compute颤振方法。

如果您需要显示完整列表(如果需要,可以分页),它可能涉及一些智能编码,但我认为没有什么可以阻止您“在后台”执行您需要的操作,即不阻塞 UI。

于 2019-08-13T12:59:35.810 回答