2

My app is a hybrid html5 + JS + android which run in webview and communicate so much with Andorid through JS interface.

I got some report that it fails after 2 second on some devices. I added ACRA so I can get reports, but I didn't get any thing.

So I tried to test it myself, To raise an exception I add a code that manipulate views of main thread in Javascript interface's function which was triggered with a button in html. This raise an exception: Only the original thread that created a view hierarchy can touch its views. Now the app start and when I tap the button it exit with exception and ACRA send the report.

Then I put the manipulation code in a function of JS interface which was called immediately after the app start. now app is closed after a second. But ACRA doesn't send any error. Even an ExceptionHandler didn't catch it but catch the first case.

This is the log of second scenario:

59): Starting input on non-focused client com.android.internal.view.IInputMethodClient$Stub$Proxy@43f8d990 (uid=10019 pid=329)
12-15 01:18:07.047: WARN/dalvikvm(409): JNI WARNING: JNI method called with exception raised
12-15 01:18:07.047: WARN/dalvikvm(409): in Landroid/webkit/BrowserFrame;.stringByEvaluatingJavaScriptFromString (Ljava/lang/String;)Ljava/lang/String; (NewString)
12-15 01:18:07.057: WARN/dalvikvm(409): Pending exception is:
12-15 01:18:07.057: INFO/dalvikvm(409): Landroid/view/ViewRoot$CalledFromWrongThreadException;: Only the original thread that created a view hierarchy can touch its views

I don't know what this pending exception is? I couldn't find anything on web. I wonder why dont ACRA or Exception Handler catch it?

class JavaScriptInterface
{
    MyActivity parent;
    JavaScriptInterface(MyActivity parent)
    {
        this.parent = parent;
    }

    public void immediatelyCalled() 
    // Webview load index.html in oncreate of activity and js inside html calls this function immediately
    {
        parent.textview1.setText("test"); 
        // raise an exception which ACRA or Exception Handler dont catch
        // Problem is here
    }

    public void buttonCalled() 
    // This is called when a button is tapped in html
    {
        parent.textview1.setText("test"); 
        // raise an exception which Exception Handler and ACRA catch
    }
}

this is my activity:

public class MyActivity extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
setContentView(R.layout.main);

        class MyExceptionHandler implements Thread.UncaughtExceptionHandler
        {
            @Override
            public void uncaughtException(Thread thread, Throwable throwable)
            {
                Log.d("ExceptionHandler", "Caught exception: " + throwable.getClass().getName() + ": " + throwable.getMessage());
            }
        }

        MyExceptionHandler handler = new MyExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(handler);


        this.wv = (WebView) findViewById(R.id.webview);
        this.wv.addJavascriptInterface(new JavaScriptInterface(this), "android");
        this.ws = this.wv.getSettings();
        this.ws.setJavaScriptEnabled(true);
        this.wv.loadUrl("file:///android_asset/index.html");

    }
}

this is part of index.html:

<script type="text/javascript">
android.immediatelyCalled();
</scritp>
<button onclick="android.buttonCalled()"></button>

Tested on AVD 2.2 and Xperai Arc 4.0.3, Both the same

Ali
  • 21,572
  • 15
  • 83
  • 95
  • I didn't use the technique combo you are doing, but the exception occurs while executing native code (JNI) as far as i understand. Could you enhance your question with the code where you are provoking the exception? I can imagine the exception is pending, because the code is executed asynchronously. – Diego Frehner Dec 14 '12 at 22:46
  • @DiegoFrehner I added JS interface code. Thank you – Ali Dec 14 '12 at 23:00

1 Answers1

2

I think the method immediatelyCalled() is called in another thread than the one you are creating "MyActivity parent" (a UI thread, your apps main thread). So an uncaught exception handler which you assign to the ui thread and which has nothing to do with the process which is running the javascript code, can not catch this exception occuring at setText (accessing a view which belongs to another thread).

I think you could catch the exception of course if you enclose parent.textview1.setText("test"); in a try catch block. You should be able to avoid the exception if you modify the setText call in this way:

parent.textView1.post(new Runnable() {
    public void run() {
        parent.textview1.setText("test");
    }
});

You'll have to mark your parent parameter as final. Unfortunately i have no eclipse here to test and it's late already :) good luck!

Diego Frehner
  • 2,396
  • 1
  • 28
  • 35
  • Thank you so much, Try Catch block catch it, and I use handlers for such scenarios. It was just interesting for me that not a exception handler nor ACRA can catch this exception. It's a strange behavior. – Ali Dec 14 '12 at 23:43
  • I have no idea what is wrapping the js execution :) But did it work with posting the operation to the right thread? – Diego Frehner Dec 14 '12 at 23:50
  • Yes, it works with a handler and it's the way I always do this. I just did so to create some exception to test ACRA, as I knew it would raise exception, but I encountered with this situation that ACRA can't catch such exceptions :)) – Ali Dec 15 '12 at 00:09
  • My answer gives you the answer ;) It is because the js code is not executed in the context of your android application. So acra which is "injected" just to your application can not track this execption. do you understand now? if so you could accept ;) it works with a handler because the handler has the same process context as the js code execution. – Diego Frehner Dec 15 '12 at 00:19
  • Yes, I got it. But I wonder why if it's called later it will be in the same thread!? – Ali Dec 15 '12 at 00:37
  • Do you wonder why it is able to catch the button click, but not the immediatelyCalled? I don't know :D. I'd assume the button click js code runs in a context associated to your webview which is associated to your android app. the immediately called will probably run in another context because it's pure js not bound to any web (html) control. – Diego Frehner Dec 15 '12 at 00:58