我一直在研究一个问题,即在一个WebView(带有返回值)中对JavaScript进行同步调用,并试图缩小它为什么不起作用的地点和原因.WebView当主线程正在等待来自它的响应时,似乎线程正在阻塞 - 自从在WebView单独的线程上运行以来不应该是这种情况.

我把这个小样本放在一起,相当清楚地展示了它(我希望):

main.xml中:

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:weightSum="1">

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:id="@+id/webView"/>

MyActivity.java:

package com.example.myapp;

import android.app.Activity;

import android.os.Build;

import android.os.Bundle;

import android.util.Log;

import android.webkit.WebSettings;

import android.webkit.WebView;

import android.webkit.JavascriptInterface;

import android.webkit.WebViewClient;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.TimeUnit;

public class MyActivity extends Activity {

public final static String TAG = "MyActivity";

private WebView webView;

private JSInterface JS;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

webView = (WebView)findViewById(R.id.webView);

JS = new JSInterface();

webView.addJavascriptInterface(JS, JS.getInterfaceName());

WebSettings settings = webView.getSettings();

settings.setJavaScriptEnabled(true);

webView.setWebViewClient(new WebViewClient() {

public void onPageFinished(WebView view, String url) {

Log.d(TAG, JS.getEval("test()"));

}

});

webView.loadData("Test", "text/html", "UTF-8");

}

private class JSInterface {

private static final String TAG = "JSInterface";

private final String interfaceName = "JSInterface";

private CountDownLatch latch;

private String returnValue;

public JSInterface() {

}

public String getInterfaceName() {

return interfaceName;

}

// JS-side functions can call JSInterface.log() to log to logcat

@JavascriptInterface

public void log(String str) {

// log() gets called from Javascript

Log.i(TAG, str);

}

// JS-side functions will indirectly call setValue() via getEval()'s try block, below

@JavascriptInterface

public void setValue(String value) {

// setValue() receives the value from Javascript

Log.d(TAG, "setValue(): " + value);

returnValue = value;

latch.countDown();

}

// getEval() is for when you need to evaluate JS code and get the return value back

public String getEval(String js) {

Log.d(TAG, "getEval(): " + js);

returnValue = null;

latch = new CountDownLatch(1);

final String code = interfaceName

+ ".setValue(function(){try{return " + js

+ "+\"\";}catch(js_eval_err){return '';}}());";

Log.d(TAG, "getEval(): " + code);

// It doesn't actually matter which one we use; neither works:

if (Build.VERSION.SDK_INT >= 19)

webView.evaluateJavascript(code, null);

else

webView.loadUrl("javascript:" + code);

// The problem is that latch.await() appears to block, not allowing the JavaBridge

// thread to run -- i.e., to call setValue() and therefore latch.countDown() --

// so latch.await() always runs until it times out and getEval() returns ""

try {

// Set a 4 second timeout for the worst/longest possible case

latch.await(4, TimeUnit.SECONDS);

} catch (InterruptedException e) {

Log.e(TAG, "InterruptedException");

}

if (returnValue == null) {

Log.i(TAG, "getEval(): Timed out waiting for response");

returnValue = "";

}

Log.d(TAG, "getEval() = " + returnValue);

return returnValue;

}

// eval() is for when you need to run some JS code and don't care about any return value

public void eval(String js) {

// No return value

Log.d(TAG, "eval(): " + js);

if (Build.VERSION.SDK_INT >= 19)

webView.evaluateJavascript(js, null);

else

webView.loadUrl("javascript:" + js);

}

}

}

运行时,会产生以下结果:

Emulator Nexus 5 API 23:

05-25 13:34:46.222 16073-16073/com.example.myapp D/JSInterface: getEval(): test()

05-25 13:34:50.224 16073-16073/com.example.myapp I/JSInterface: getEval(): Timed out waiting for response

05-25 13:34:50.224 16073-16073/com.example.myapp D/JSInterface: getEval() =

05-25 13:34:50.225 16073-16073/com.example.myapp I/Choreographer: Skipped 239 frames! The application may be doing too much work on its main thread.

05-25 13:34:50.235 16073-16150/com.example.myapp I/JSInterface: returning Success

05-25 13:34:50.237 16073-16150/com.example.myapp D/JSInterface: setValue(): Success

(16073是'主要'; 16150是'JavaBridge')

正如您所看到的,主线程超时等待WebView调用setValue(),直到latch.await()超时并且主线程执行仍在继续.

有趣的是,尝试使用早期的API级别:

Emulator Nexus S API 14:

05-25 13:37:15.225 19458-19458/com.example.myapp D/JSInterface: getEval(): test()

05-25 13:37:15.235 19458-19543/com.example.myapp I/JSInterface: returning Success

05-25 13:37:15.235 19458-19543/com.example.myapp D/JSInterface: setValue(): Success

05-25 13:37:15.235 19458-19458/com.example.myapp D/JSInterface: getEval() = Success

05-25 13:37:15.235 19458-19458/com.example.myapp D/MyActivity: Success

(19458是'主'; 19543是'JavaBridge')

事情按顺序正常工作,getEval()导致WebView调用setValue(),然后latch.await()在超时之前退出(正如您所期望/希望的那样).

(我也尝试过更早的API级别,但是由于我所理解的,2.3.3中一个从未修复的模拟器错误可能会导致崩溃.)

所以我有点失落.在挖掘中,这似乎是正确的做事方法.它看起来似乎是正确的方法,因为它在API级别14上正常工作.但是后来的版本失败了 - 我在5.1和6.0上测试没有成功.

android如何阻塞主线程,Android主线程阻塞WebView线程相关推荐

  1. android判断主线程_Android主线程和子线程区别详解

    主线程和子线程的区别 每个线程都有一个唯一标示符,来区分线程中的主次关系的说法. 线程唯一标示符:Thread.CurrentThread.ManagedThreadID; UI界面和Main函数均为 ...

  2. Android线程之主线程向子线程发送消息

    和大家一起探讨Android线程已经有些日子了,谈的最多的就是如何把子线程中的数据发送给主线程进行处理,进行UI界面的更新,为什么要这样,请查阅之前的随笔.本篇我们就来讨论一下关于主线程向子线程如何发 ...

  3. python主辅线程_python主线程捕获子线程的方法

    最近,在做一个项目时遇到的了一个问题,主线程无法捕获子线程中抛出的异常. 先看一个线程类的定义 ''''' Created on Oct 27, 2015 @author: wujz ''' impo ...

  4. python主线程_Python主线程和子线程

    Python主线程和子线程 一.setDaemon(False) 当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行的最小单位,当设置多线程时,主线程会创建多个子线程,在Python中,默认 ...

  5. java 获取子线程_Java 主线程获取子线程返回结果

    1.自定义 package com.jgyang.com; public class MySyncThreadTest { public static void main(String[] args) ...

  6. c++主线程等待子线程结束_简单明了的 Python 多线程来了 | 原力计划

    作者 | 万里羊责编 | 王晓曼出品 | CSDN博客线程和进程计算机的核心是CPU,它承担了所有的计算任务,就像是一座工厂在时刻运行.如果工厂的资源有限,一次只能供一个车间来使用,也就是说当一个车间 ...

  7. pthread_detach():主线程与子线程分离,子线程结束后,资源自动回收

    https://github.com/Rtoax/test/tree/master/c/glibc/pthread 目录 前言 pthread_join() pthread_detach() 前言 1 ...

  8. 多线程——主线程和子线程退出关系

    分清两个概念 主线程和当前进程的关系:当前进程由主线程和若干个子线程组成. 若当前进程退出后,子线程也会跟着一起退出:若只是主线程退出,仍要分两种情况分析:实际上主线程退出后子线程的状态依赖于它所在的 ...

  9. Android,UI主线程与子线程

    在一个Android 程序开始运行的时候,会单独启动一个Process.默认的情况下,所有这个程序中的Activity或者Service(Service和 Activity只是Android提供的Co ...

  10. android 线程传递数据,Android Handle主线程向子线程发送数据

    一.前言: 今天,下载apk的时候,下载进度回调到主线程,主线程刷新通知栏,造成页面阻塞掉,不能点击页面(下载结束后,可以正常点击页面). 所以,要在进度回调发送消息到子线程,在子线程的Handler ...

最新文章

  1. android序列化异常,关于序列化:错误:Android中的序列化和反序列化
  2. leetcode算法题--二叉树的锯齿型层次遍历
  3. DescriptionAttribute Class
  4. 实录 | 平安人寿资深算法工程师张智:人机交互场景下的知识挖掘
  5. VTK:绘图之BoxChart
  6. add to -append Backend implementation
  7. C#中的DES加解密方法
  8. 手把手教你如何逐步安装OpenStack
  9. java中service设计_JDBC中DAO+service设计思想
  10. 火狐扩展教程_Firefox扩展模板
  11. epc项目设计流程图_EPC工程总承包管理流程图解。
  12. 卡尔曼滤波算法-Matlab仿真
  13. 一个非常好用的免费图床
  14. english 后缀
  15. 边做边学入门微信小程序之仿豆瓣评分
  16. ISE 下按键消抖实验
  17. 3D建模软件应该学中文版还是英文版?Maya软件应该学中文版还是英文版?
  18. maven pc配置要求_竞速游戏《F1 2019》PC配置要求 GTX 1660ti即可畅玩
  19. 洞见—微服务文集(二)
  20. trc20和erc20、OMNI有什么区别

热门文章

  1. 【转】nodejs更新mysql数据库信息
  2. prototype.js学习(2)
  3. 负载均衡之LVS详解
  4. 决策树-Cart算法二
  5. 静态库与动态库的制作
  6. 单例模式专集细节讲述
  7. 极客学院视频教程学习笔记-iOS中CALayer的使用
  8. centos 6.2网卡配置
  9. 使用jQuery的load方法实现div局部刷新
  10. 判断 失效_复合材料渐进失效Hashin模型及参数详解