在Android中使用WebView实现JavascriptInterface的最佳实践?

时间:2016-06-24 20:54:29

标签: java android multithreading webview

我遇到了与此问题相同的错误的崩溃报告:WebView methods on same thread error

建议创建一个Runnable()。

我不明白为什么这才能解决问题。该错误在同一个Thread"上显示" Webview方法,但答案建议在UI-Thread(主线程)上创建该方法。但是不是UI-Thread唯一的线程吗?有人可以详细解释整个过程(考虑到我在构造函数中的每个活动中创建一个新的Webview)?

我实现Javascript函数/方法的代码如下所示:

public class JS_Bind {
    private static final String TAG = "JS_Bind";
    private Context context;
    private AdvancedWebView mWebView;

    public JS_Bind(Context c, AdvancedWebView mWebView) {
        context = c;
        this.mWebView = mWebView;
    }
    @JavascriptInterface
    public void openActivity(String activityName) {
        try {
            Class activityClass = Class.forName(PACKAGE_NAME + "." + activityName);
            context.startActivity(new Intent(MainActivity.this, activityClass));
        } catch (ClassNotFoundException e) {
            Toast.makeText(context, "Invalid activity name: " + activityName, Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }
    @JavascriptInterface
    public void makeToast(String toast) {
        Toast mToast = Toast.makeText(context, toast, Toast.LENGTH_SHORT);
        mToast.setGravity(Gravity.CENTER, 0, 0);
        mToast.show();
    }
    @JavascriptInterface
    public void external(String url) {
        mTracker.send(new HitBuilders.EventBuilder().setCategory("Action").setAction("External Link: " + url).build());
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
    }
    @JavascriptInterface
    public String showToken() {
        return gcmToken;
    }
    @JavascriptInterface
    public int showUid() {
        SharedPreferences pref = getSharedPreferences("Pref", Activity.MODE_PRIVATE);
        int uid = pref.getInt("uid", 0);
        return uid;
    }
    @JavascriptInterface
    public void buyPremium() {
        bp.purchase(MainActivity.this, PRODUCT_ID);
    }
}

我是否必须将每个函数更改为此代码(first answer in the question I refered to):

@JavascriptInterface
    mWebView.post(new Runnable() {
        @Override
        public void makeToast() {
          // ...
        }
    });

顺便说一句,这就是我在构造函数活动onCreate方法中创建webview的方法:

mWebView = (AdvancedWebView) findViewById(R.id.webView);
mWebView.setListener(this, this);
mWebView.addJavascriptInterface(new JS_Bind(this, mWebView), "Android");
mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

if (!DetectConnection.checkInternetConnection(this)) {
    mWebView.loadUrl("file:///android_asset/offline.html");
}
else {
        mWebView.loadUrl("http://example.com/tw3/index.php?s=home");
}

1 个答案:

答案 0 :(得分:1)

  

但是UI-Thread不是唯一的线程吗?

没有。 WebView有自己的线程池。可以有many other threads in an Android application

  

我是否必须将每个功能更改为此代码

不一定。

首先,我不知道您是如何从上面显示的A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread.方法中获得该错误(@JavascriptInterface)的。该错误是在WebView本身上调用方法时,您没有这样做。

如果符合以下条件,您将需要使用runOnUiThread()(或等效技术)

  • 您的@JavascriptInterface方法是指WebView本身,或

  • 您的@JavascriptInterface尝试在主应用程序线程上执行必须执行的其他操作(这将产生不同的错误消息,因为它不会专门与WebView绑定)

可能需要在主应用程序线程上调用startActivity()调用 - 我忘了是否可以在后台线程上调用它。与您的Toast工作类似 - 虽然我认为可以在后台线程上完成,但我不确定。自从我尝试从后台线程中完成其中任何一项工作以来已经很久了。

此外,如果您控制WebView中显示的每个字节,请仅使用您的代码。将startActivity()暴露给任意Web内容具有重大的安全隐患。