3

I have some problem with calling a JavaScript function in a WebView and getting response in the app (on my Galaxy Tab 2 '10). I call the js-function directly after content loading. According this one solution i use a PictureListener

webView.setPictureListener(new PictureListener() {
        @Override
        public void onNewPicture(WebView view, Picture picture) {
            webView.loadUrl("javascript: JsImpl.init('{response}');");
        }
});

it works fine: when content is loaded, onNewPicture always is started. "javascript: JsImpl.init('{response}') loads js that calls:

class JsImpl {
    private final static String LOG_TAG = "JsImpl";

    @JavascriptInterface
    public void init(String json) {
        Log.d(LOG_TAG, json);
    }
}

In the log i see D/JsImpl(18400): {response}. It seems to be everything okay but...

When I switch my tab on a landscape or portrait mode the WebView is recreated, onNewPicture are started but the method public void init(String json) in the JsImpl is often not called at all!

So if i change orientation, sometimes js works, sometimes doesn't work. No exception, no errors...

Who faced with the same problem?

Below is full code

public class NextActivity extends Activity {

@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_next);

    final WebView wv = (WebView) findViewById(R.id.WebView);
    wv.getSettings().setJavaScriptEnabled(true);
    wv.loadUrl("file:///android_asset/index.html");
    wv.addJavascriptInterface(new JsImpl(), "JsImpl");

    wv.setPictureListener(new PictureListener() {
        @Override
        public void onNewPicture(WebView view, Picture picture) {
            wv.loadUrl("javascript: JsImpl.init('{responce}');");
        }
    });
}

class JsImpl {
    private final static String LOG_TAG = "JsImpl";

    @JavascriptInterface
    public void init(String json) {
        Log.d(LOG_TAG, json);
    }
}

}

html code is not needed here, just put on the assets dir an empty html file index.html.


EDIT: I've found one soution but i dont know exactly is it correct varion. But it works. I added handler loop

 final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if (isJSSetup) return;
            Log.i("handler-loop", "JS didn't handle. Reload page");
            wv.loadUrl(CONTENT_PAGE);
            handler.postDelayed(this, 1000);
        }
    }, 1000);

when @JavascriptInterface init(String json) is called, isJSSetup became true. In handler loop i check if JS is setup or no if (isJSSetup) return;. If no - i reload URL again wv.loadUrl(CONTENT_PAGE) and try to call init(String json). So long as it is not going to work. It's hardcode, so i'm still looking for a good solution.

Community
  • 1
  • 1
validcat
  • 6,158
  • 2
  • 29
  • 38

1 Answers1

1

I hope this will help, but I can't say for sure because you are not showing how your WebView is restored after orientation changes.

I was having very hard time making my nested fragments to work properly after orientation changes. I wanted to retain the form values and all functionality during screen rotations. It all worked fine except the JavascriptInterface was NEVER working after orientation changes.

My WebView is restored in the onCreateView. I had to remove the restoreState call for my WebView and it all works now.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    rootView = inflater.inflate(R.layout.layoutT4, container, false);
    webView = (WebView) rootView.findViewById(R.id.webViewT4);
    prepareBrowser();   // the browser is initiated here including the JavascriptInterface

    if (webView != null) {
        String URL = (savedInstanceState == null) ? "" : savedInstanceState.getString("URL");
        if (URL.equals("")) {
            webView.loadUrl("yourhome.html");    
        } else {
            //webView.restoreState(savedInstanceState.getBundle("webViewBundle"));  // this line was preventing the JavascriptInterface to work properly
            webView.loadUrl(URL);   // this is saved in onSaveInstanceState - I just reopen the URL here, the PHP page will take care of reloading the data
        }
    }
    return rootView;
}
theczechsensation
  • 4,215
  • 2
  • 24
  • 25
  • so if u restore webview state from savedInstanceState (webView.restoreState(savedInstanceState.getBundle("webViewBundle"))) it always work fine? – validcat Dec 26 '13 at 08:28
  • On the contary, the restoreState did not seem to have any positive effect and I confirmed that this was the only line of code breaking functionality of my JavascriptInterface. I also did not see that the webView.saveState() was storing the URL, so I ditched it. If I browse from URL1 to URL2 and rotate the phone, restoreState() will return me to URL1. So I just store the webView.getUrl() on onSaveInstanceState and point the browser back to where I was. The reloaded URL2 contains all the data I need. – theczechsensation Dec 27 '13 at 04:04