【问题标题】:Emulate Web Workers in Android pre- Kitkat在 Android pre-Kitkat 中模拟 Web Workers
【发布时间】:2014-03-15 19:53:39
【问题描述】:

由于 Webworkers 仅从 Android 4.4 开始实现,是否可以在应用程序代码中包含一个包装器,为包含的 WebView 提供此功能?

一个关于如何解决这个问题的例子真的很有帮助。

谢谢,
拉贾特

【问题讨论】:

    标签: android webview web-worker


    【解决方案1】:

    我猜你说的是在后台运行一个 javascript 代码块,即不同的线程。曾尝试在 Android 上使用 RhinoJS 来做到这一点。在 Android 2.2 及更高版本上测试

    https://github.com/devthon/SilentJSAndroid

    主要特点是

    1. 在没有浏览器上下文的情况下执行 Javascript 代码
    2. 从脚本文件执行 Javascript 代码
    3. 在同一上下文中加载其他 JS 文件
    4. 在后台线程中执行方法并返回结果
    5. 执行 Object.Method() 调用
    6. 执行原型方法调用
    7. 应用关闭后在后台运行长时间运行的脚本。

    可能不是一个成熟的网络工作者,因为它没有 API 来检查两者之间的状态。但是我相信仍然可以将其添加到界面中。

    如果这是您正在寻找的方向,我可以详细解释它是如何完成的。

    【讨论】:

    【解决方案2】:

    您需要实施多少 Worker 规范,实施需要有多灵活?您可能可以使用 JavaScript 接口 [1] 启动并运行基本功能,并从 Java 本地生成线程。但是,这会很快变得复杂。

    也许如果你能描述一下你使用工人的原因,我可能会提供一个不同/更好的建议。

    [1] http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)

    --

    添加一些伪代码

    在 JavaScript 中生成一个 Java 工作线程:

    var worker_id = window.Android.spawnWorker();
    

    在 JavaScript 中,在该 worker 上运行一个任务:

    var task_id = window.Android.doAdditionOnWorker(2,2, worker_id);
    

    在 JavaScript 中处理结果

    function onReceiveResultForWorkerTask(task_id, result) {
        alert("the answer was " + result);
    }
    

    Java端:

    public int spawnWorker() {
        HandlerThread worker = new HandlerThread();
        worker.start();
        Handler h = new Handler(worker.getLooper()) {
            @Override
            handleMessage(Message msg) {
               switch(msg.what) 
               case ADD:
                   // calculate the answer and send back to JS via UI thread
                   // Unpack parameters and task id from Message               
                   mWebView.post(new Runnable(
                       public void run() {
                           mWebView.loadUrl("javascript:onReceiveResultForWorkerTask(task_id, " + (a+b) +");");
                       }
                   )
            }
        };
    
        mWorkerMap.put(mWorkerId++, h);
        return mWorkerId;
    }
    
    public int doAdditionOnWorker(int a, int b, int worker_id) {
        Handler h = mWorkerMap.get(worker_id);
        Bundle b = new Bundle();
        int task_id = mTaskId++;
        // pack arguments and task_id into the bundle
        h.postMessage(Message.obtain(h, ADD, b);
        return task_id;
    }
    

    当应用不再需要它们时,不要忘记检查并拆除您生成的所有工作线程。根据您需要的工作线程数量,您可能还更喜欢使用线程池,而不是每次都创建新线程。

    【讨论】:

    • 我们正在使用 addJavascriptInterface() 注入一个从 Javascript 代码调用的 Java 对象。该 JS 层轮询一个函数以获取 Java 层需要发送的任何未决消息(以避免使用 loadUrl())。
    • 针对您的具体问题,考虑到我们使用的是轮询方法(如我之前的评论中给出的),有没有办法使用不同的 Java 线程来模拟 Webworkers?
    • 好吧,您可以生成一个 Java 线程来响应来自 JavaScript 的回调,并将该线程的标识符返回给您的 JavaScript。然后,JavaScript 可以使用标识符向该 Java 线程发送消息,再次通过 JavaScript 接口返回。我猜原生 Java 线程会运行一个 Handler 来接收要做什么的消息。
    • 我不明白这是什么意思。 Javascript 是如何向 Java 线程发送消息的?
    • 通过 JavaScript 桥再次调用 java。您将通过处理程序将消息代理到本机线程。将结果传回也很棘手;您需要将消息从“worker”发送回应用程序 UI 线程,然后加载一个 javascript: URL 来发送它。请记住,您也只能跨 JS/Java 边界发送原始类型,因此您需要先将 JS 对象序列化为字符串。这很复杂,从来没有说过这很容易:-)
    猜你喜欢
    • 1970-01-01
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-09
    • 1970-01-01
    • 2017-10-22
    相关资源
    最近更新 更多