1

Since Webworkers is only implemented from Android 4.4 onwards, is it possible to have a wrapper in the application code that provides this functionality to the contained WebView?

An example on how to solve this would really help.

Thanks,
Rajath

Rajath
  • 11,787
  • 7
  • 48
  • 62

2 Answers2

1

I guess you are talking about running a javascript code block in the background, i.e. different thread. Had tried doing that using RhinoJS on Android. Tested on Android 2.2 and above

https://github.com/devthon/SilentJSAndroid

The main features are

  1. Execute Javascript code without browser context
  2. Execute Javascript code from a script file
  3. Load other JS files in the same context
  4. Execute a method in the background thread and return a result
  5. Execute a Object.Method() call
  6. Execute a prototype method call
  7. Run long running script in the background after app is closed.

May not be a full fledged Web worker as such, since it doesn't have API to check the status in between. But that can be still added to the interface I believe.

If this is the direction you are looking for, I can explain more on how it is done.

aravind
  • 2,867
  • 17
  • 28
  • Thanks Aravind. I think that's what I was looking for - will give it a try. – Rajath Mar 16 '14 at 14:05
  • Just wanted to add some URLs that might be useful for others: 1) http://divineprogrammer.blogspot.com/2009/11/javascript-rhino-on-android.html , 2) http://openaphid.github.io/blog/2013/01/17/part-i-how-to-choose-a-javascript-engine-for-ios-and-android-apps/ , 3) https://developer.mozilla.org/en-US/docs/Rhino/Download_Rhino – Rajath Mar 18 '14 at 09:42
0

How much of the Worker spec do you need to implement, and how flexible does the implementation need to be? You could probably get basic functionality up and running using a JavaScript interface[1] and spawning threads natively from Java. However this will get complex quite quickly.

Perhaps if you can describe what you are using workers for I might be able to offer a different/better suggestion.

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

--

Adding some pseudo code

In JavaScript spawn a Java worker thread:

var worker_id = window.Android.spawnWorker();

In JavaScript, run a task on that worker:

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

Handle the result in JavaScript

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

Java side:

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;
}

Don't forget to go through and tear down all the worker threads that you spawn when the app doesn't need them anymore. Depending on how many workers you need you might also prefer to use a thread pool rather than creating new threads every time.

ksasq
  • 4,424
  • 2
  • 18
  • 10
  • We are using addJavascriptInterface() to inject a Java object that is called from the Javascript code. This JS layer polls a function to pick up any pending messages that the Java layer needs to send (to avoid using loadUrl()). – Rajath Mar 11 '14 at 11:33
  • To your specific question, and considering that we are using the polling method (as given in my previous comment), is there a way to use different Java threads to emulate Webworkers? – Rajath Mar 11 '14 at 11:34
  • Well, you could spawn a Java thread in response to a callback from JavaScript, and return an identifier for that thread to your JavaScript. The JavaScript could then send messages to that Java thread using the identifier, again back over the JavaScript interface. I guess the native Java thread would be running a Handler to receive the messages of what to do. – ksasq Mar 11 '14 at 12:29
  • I don't understand what that means. How does the Javascript send messages to the Java thread? – Rajath Mar 12 '14 at 04:30
  • By calling out to java again via the JavaScript Bridge. You'd proxy the message to the native thread via a Handler. Passing the result back is tricky too; you'd need to send a message back from the "worker" to the apps UI thread, and then load a javascript: URL to send it. Bear in mind that you'll also only be able to send primitive types across the JS/Java boundary, so you'll need to serialise JS objects to strings first. This is complicated, never said it would be easy :-) – ksasq Mar 12 '14 at 08:29
  • I'm already aware of the basic use of javascript bridge with Java. But I don't understand your explanation of emulation of Web workers. Can you please show this in the form of some example? Thanks. – Rajath Mar 12 '14 at 10:29
  • Added some pseudocode to help elucidate what I'm getting at. – ksasq Mar 12 '14 at 11:23
  • Thanks ksasq; let me try this and get back. – Rajath Mar 13 '14 at 10:01
  • I tried to print and sleep in the javascript code based on a call from the java code; the latter being called via loadUrl() from a different thread each time. It looks like all the code in javascript ends up running on the same thread. So, I don't think this works. – Rajath Mar 14 '14 at 11:33
  • Maybe it's not even possible. According to http://stackoverflow.com/questions/3631507/method-to-get-the-running-thread-id-in-javascript-jquery, there is no concept of threads in javascript. So, maybe there is only one thread, irrespective of attempting to spawn from different java threads. – Rajath Mar 14 '14 at 11:34
  • yes, the WebView is single threaded wrt. javascript execution. I'm not sure what you mean by printing and sleeping in your javascript; you need to be doing everything asynchronously. With the code I prototyped you are offloading a calculation initiated from javascript to a background java thread, and sending the result back to javascript asynchronously. It's not really a replacement for workers, but I think it's the closest you will be able to get. – ksasq Mar 14 '14 at 11:44
  • OK. But I need to be able to run javascript code itself in a different thread. Apologies if my question was not understandable. – Rajath Mar 14 '14 at 11:45
  • I don't think that's possible prior to Android 4.4, I'm afraid. – ksasq Mar 14 '14 at 13:30