使用哪个线程进行Cordova插件的回调?

8
在哪个线程中应该调用CallbackContext的方法? CordovaPlugin#execute(...)的文档说明它在WebView线程中调用。这和UI线程相同吗?如果是,那可能就是我的答案。
如果WebView线程不是UI线程,并且我应该在WebView线程中回调,是否可以异步地实现呢?
1个回答

7
我为你提供Android插件文档中的线程部分翻译:
这些插件都是异步的,当你调用它们时,会得到一个成功或失败的回调。如果本地任务太长,线程只是为了不阻塞UI。
引用如下: 线程 插件的JavaScript不在WebView接口的主线程中运行;相反,它在WebCore线程上运行,execute方法也是如此。如果需要与用户界面交互,您应该使用以下变体:
@Override
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
    if ("beep".equals(action)) {
        final long duration = args.getLong(0);
        cordova.getActivity().runOnUiThread(new Runnable() {
            public void run() {
                ...
                callbackContext.success(); // Thread-safe.
            }
        });
        return true;
    }
    return false;
}

如果您不需要在主界面线程上运行,但也不想阻塞WebCore线程,请使用以下内容:
@Override
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
    if ("beep".equals(action)) {
        final long duration = args.getLong(0);
        cordova.getThreadPool().execute(new Runnable() {
            public void run() {
                ...
                callbackContext.success(); // Thread-safe.
            }
        });
        return true;
    }
    return false;
}

http://docs.phonegap.com/en/3.5.0/guide_platforms_android_plugin.md.html#Android%20Plugins

Kevin的说明:

调用CallbackContext方法最终会调用CordovaWebView#sendPluginResult(PluginResult cr, String callbackId)。在CordovaWebViewImpl中实现该方法时,会调用NativeToJsMessageQueue#addPluginResult(cr, callbackId),最终导致在同步块内添加一个元素到LinkedList中。所有对该List的访问都是同步的。


2
这些示例彼此矛盾。一个在UI线程中调用回调函数,另一个在工作线程中调用回调函数。你真的是在告诉我没有关于回调发生在哪个线程的约定吗?通常情况下,这不仅仅是一个约定;它将是由execute(...)的契约指定的保证。 - Kevin Krumwiede
不,有三种调用execute的方式。 "正常"方式在WebCore线程中执行callbackContext。但是您可以在UI线程(第一个示例)或与WebCore和UI线程不同的另一个线程上执行callbackContext(第二个示例)。它们都是异步的。如果您不介意阻塞UI,则可以选择任何一种方式;如果您不想阻塞它,请使用UI线程;如果要执行的代码无法在UI线程上运行,则使用第二个示例。 - jcesarmobile
1
看起来你说的在随机工作线程中调用回调函数没问题。原因如下。你能把这个加到你的答案里吗?对CallbackContext方法的调用最终会调用CordovaWebView#sendPluginResult(PluginResult cr, String callbackId)。在CordovaWebViewImpl中实现该方法时,会调用NativeToJsMessageQueue#addPluginResult(cr, callbackId),这最终导致在synchronized块内添加一个元素到LinkedList中。所有对该列表的访问都是同步的(除了一个——我会提交一个bug)。 - Kevin Krumwiede
我已将您的评论添加到答案中。 - jcesarmobile
你能澄清一下这个注释吗?这是否意味着最终 callbackContext.success() 总是线程安全的,并且将在 UI 线程上运行? - Nathan H
我认为这只是意味着它是同步的,但不在UI线程上。如果您想在UI线程上运行代码,请使用runOnUiThread。无论如何,callbackContext.success();通常不需要花费很长时间运行(除非您返回一个大值),您需要担心阻止UI的代码是插件执行的其余代码。 - jcesarmobile

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接