evgenyneu / js-evaluator-for-android

A library for running JavaScript in Android apps.
MIT License
487 stars 84 forks source link

How to wait for the callback function? #7

Open ypid opened 10 years ago

ypid commented 10 years ago

Hi

do you know a good way to turn the event driven programming into non-event driven. Lets say you want to define a function like the following example:

    protected String getDate() {
        mJsEvaluator.evaluate("new Date().toString()", new JsCallback() {
            @Override
            public void onResult(final String resultValue) {
                Log.d("Date", String.format("Result: %s", resultValue));
                // Block until event occurs.
            }
        });
        return "value of resultValue";
    }

I have read some code in your test app:

    @MediumTest
    public void testEvaluateJQuery() throws InterruptedException {
        final TextView resultTextView = (TextView) mActivity
                .findViewById(R.id.realLibraryResultJqueryView);

        final String expectedResult = "Result: jQuery is working!";

        for (int i = 0; i < 100; i++) {
            Thread.sleep(100);
            if (resultTextView.getText().equals(expectedResult)) {
                break;
            }
        }
        assertEquals(expectedResult, resultTextView.getText());
    }

Is this the way to go?

evgenyneu commented 10 years ago

@ypid, I suspect that using Thread.sleep on UI thread will freeze the UI. Personally I would absolutely avoid doing that in the app. It is ok in the tests - because, well, they are just tests.

ypid commented 10 years ago

@evgenyneu Thanks for the info. What if you would put all that in a service? Could you maybe add an example to the test program? I guess the need for a blocking API is kind of common (it would be very helpful at least for me who is trying to write a wrapper class for a JavaScript library)?

evgenyneu commented 10 years ago

@ypid definitelly, synchronous execution can be a very common use case. I will investigate what's the best approach and will put an example in README. Thanks for the feedback.

ypid commented 10 years ago

Thanks very much … I am looking forward to your investigation.

tom91136 commented 10 years ago

Simply using a CountDownLatch would work, or you can create a Future to make it modular...

Somthing like this using a CountDownLatch:

            final CountDownLatch latch = new CountDownLatch(1);
            final MutableObject<String> result = new MutableObject<>();
            handler.post(new Runnable() {
                @Override
                public void run() {
                    webView.evaluateJavascript(js, new ValueCallback<String>() {
                        @Override
                        public void onReceiveValue(String value) {
                            result.setValue(value);
                            latch.countDown();
                        }
                    });
                }
            });
            latch.await();
            result.getValue();
tom91136 commented 10 years ago

That's the idea, swap out the webView part and put your asynchronus callback in there; The MutableObject is just a simple Object wrapper from commons lang, it's trivial to implement yourself if you don't want the added weight of an extra library

ypid commented 10 years ago

@tom91136 Nice nice. Thanks. I will try your suggestions.

evgenyneu commented 10 years ago

Thanks @tom91136, appreciate your help.

nouhcc commented 6 years ago

thanks a lot @tom91136