Android 混合了 JSON 的 Android 应用程序

通过WebView在javascript里调用java 方法代码, 在java代码里执行javascript代码, 二者通过json进行数据交换

[b]设置 WebView 小部件[/b]


// connect to our browser so we can manipulate it
browser = (WebView) findViewById(R.id.calculator);

// set a webview client to override the default functionality
browser.setWebViewClient(new wvClient());

// get settings so we can config our WebView instance
WebSettings settings = browser.getSettings();

// JavaScript? Of course!
settings.setJavaScriptEnabled(true);

// clear cache
browser.clearCache(true);

// this is necessary for "alert()" to work
browser.setWebChromeClient(new WebChromeClient());

// add our custom functionality to the javascript environment
browser.addJavascriptInterface(new CalculatorHandler(), "calc");

// uncomment this if you want to use the webview as an invisible calculator!
//browser.setVisibility(View.INVISIBLE);

// load a page to get things started
browser.loadUrl("file:///android_asset/index.html");

// allows the control to receive focus
// on some versions of Android the webview doesn't handle input focus properly
// this seems to make things work with Android 2.1, but not 2.2
// browser.requestFocusFromTouch();



将一个名为 browser 的 Activity 范围变量捆绑到了 WebView 控件。WebView 是一个相当复杂的类,可高度定制。例如,您需要设置几个类,以得到与 web 浏览器相关的预期函数。这是程序员必须投入一定精力来得到一些有用函数的地方之一。但是,此定制是没有限制的。对于此应用程序的目的来说,WebView 控件已经进行了最低限度的部署。

WebViewClient 提供用于捕获各种事件的钩子,这些事件包括页面加载开始和结束、表单重新提交、键盘截取以及程序员喜欢跟踪并操纵的很多其他事件。类似地,您需要 WebChromeClient 的一个实例,用于允许诸如非常有用的 alert() JavaScript 函数之类的函数。使用 WebSettings 来为控件启用 JavaScript。


[size=x-large]连接 JavaScript 接口[/size]

下一步是启用 Activity 中的 Java 代码,以与 WebView 管理的 HTML 文件中的 JavaScript 代码交互。这是通过调用 addJavascriptInterface() 方法完成的,如 清单 4 所示。

该函数的参数是一个 Java 类的实例和一个名称空间标识符。例如,对于这个应用程序,您定义一个 calc 名称空间,并实现名为 CalculatorHandler 的类中的代码,如 清单 5 所示。

[b]清单 5. CalculatorHandler 实现[/b]

// Javascript handler
final class CalculatorHandler
{
private int iterations = 0;
// write to LogCat (Info)
public void Info(String str) {
iterations++;
Log.i("Calc",str);
}
// write to LogCat (Error)
public void Error(String str) {
iterations++;
Log.e("Calc",str);
}
// sample to retrieve a custom - written function with the details provided
// by the Android native application code
public String GetSomeFunction()
{
iterations++;
return "var q = 6;function dynamicFunc(v) { return v + q; }";
}
// Kill the app
public void EndApp() {
iterations++;
finish();
}
public void setAnswer(String a)
{
iterations++;
Log.i(tag,"Answer [" + a + "]");
}
public int getIterations()
{
return iterations;
}
public void SendHistory(String s)
{
Log.i("Calc","SendHistory" + s);
try {
JSONArray ja = new JSONArray(s);
for (int i=0;i<ja.length();i++) {
Log.i("Calc","History entry #" + (i+1) + " is [" + ja.getString(i)+ "]");
}
} catch (Exception ee) {
Log.e("Calc",ee.getMessage());
}
}
}

在 JavaScript 环境中,通过 window.calc.methodname 语法访问 CalculatorHandler 的方法。例如,CalculatorHandler 实现一个名为 Info() 的方法,后者接受一个字符串参数并将之写到应用程序日志中。要从 JavaScript 环境访问此方法,可使用类似这样的语法:window.calc.Info("write this string to the application log!");。

基本了解了如何从 JavaScript 代码调用 Java 代码之后,我们再来看 清单 6 中的 index.html 文件,看各种方法是如何被调用的。

[b]清单 6. WebView 控件中呈现(和执行)的 index.html[/b]

<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=0.25,
user-scalable=yes" />
<title>Android to JavaScript with JSON</title>
</head>
<script language="JavaScript">
var cmdHistory = new Array();
function startup() {
try {
window.calc.Info("Starting up....");
cmdHistory[cmdHistory.length] = "startup";
} catch (ee) {

}
}
function PerformSimpleCalculation(formula) {
try {
cmdHistory[cmdHistory.length] = "PerformSimpleCalculation";
var answer = eval(String(formula));
document.getElementById('data').value = answer;
window.calc.setAnswer(answer);
} catch (ee) {
window.calc.Error(ee);
}
}
function PerformComplexCalculation(andmethod) {
try {
/*
* argument to this function is a single object with 2 "members or properties"
* operation: this is a string naming what we want the function to do.
* array of arguments: this is an array of integers
*
*/
//alert(andmethod.operation);
//alert(andmethod.arguments.length);
if (andmethod.operation == "addarray") {
cmdHistory[cmdHistory.length] = "PerformCompleCalculation-addarray";
var i;
var result = 0;
for (i=0;i<andmethod.arguments.length;i++) {
result += andmethod.arguments[i];
}
document.getElementById('data').value = result;
window.calc.setAnswer(result);
}
if (andmethod.operation == "multarray") {
cmdHistory[cmdHistory.length] = "PerformCompleCalculation-multarray";
var i;
var result = 1;
for (i=0;i<andmethod.arguments.length;i++) {
result *= andmethod.arguments[i];
}
document.getElementById('data').value = result;
window.calc.setAnswer(result);
}
} catch (ee) {
window.calc.Error(ee);
}
}
function dynamicfunction()
{
try {
cmdHistory[cmdHistory.length] = "PerformCompleCalculation-dynamic";
eval(String(window.calc.GetSomeFunction()));
var result = dynamicFunc(parseInt(document.getElementById('data').value));
document.getElementById('data').value = result;
}catch (ee) {
alert(ee);
}
}
</script>
<body >
<center>
<h3>Running in Web View :)</h3>
this is some sample text here <br />
<input type="text" id="data" value="starting value"><br />
<button onclick="window.calc.Info(document.getElementById('data').value);">Log
Info</button>  
<button onclick="window.calc.Error(document.getElementById('data').value);">Log
Error</button><br />
<button onclick="dynamicfunction();">Dynamic</button>
<button onclick="alert(String(window.calc.getIterations()));">How
Many Calls</button>
<button onclick="window.calc.SendHistory(JSON.stringify(cmdHistory));">
History</button>
<button onclick="if (window.confirm('End App?')) window.calc.EndApp();">Kill This
App</button><br />
</center>
</body>
</html>


仔细研究一下 清单 6 末尾的按钮处理程序。基本上,这些按钮处理程序都调用 window.calc 名称空间中的方法,这些方法在 AndroidJSON.java 中的 CalculatorHandler 类中实现。

清单 5 和 清单 6 协同工作,演示了 JavaScript 环境中初始化的和 Java 源文件中实现的代码交互。但是如何从 Activity 代码中初始化一些您想要在 WebView 中发生的动作呢?

现在应该更深入地来看 Java 代码了。

[size=x-large]插入 JavaScript 代码[/size]

从将一个数学公式传递到 JavaScript 代码进行计算这样一个任务开始。JavaScript 最伟大(也最危险)的特性之一是 eval() 函数。eval() 函数允许字符串代码的运行时计算。在本例中,您从 EditText 控件接受一个字符串并传递到 JavaScript 环境进行计算。具体来说,我们调用 清单 6 中的 PerformSimpleCalculation() 函数。

清单 7 包含 AndroidJSON.java 中的代码,它负责处理按钮选择。

[b]清单 7. 从 Java 调用 PerformSimpleCalculation() JavaScript 函数[/b]


btnSimple.setOnClickListener(new OnClickListener()
{
public void onClick(View v) {
Log.i(tag,"onClick Simple");
// Perform action on click
try
{
String formulaText = formula.getText().toString();
Log.i(tag,"Formula is [" + formulaText + "]" );
browser.loadUrl("javascript:PerformSimpleCalculation(" + formulaText + ");");
}
catch (Exception e)
{
Log.e(tag,"Error ..." + e.getMessage());
}
}
});


不管此方法有多少行,这里唯一要关注的是 browser.loadurl() 行,它传递一个格式字符串:javascript:<code to execute>。

此 JavaScript 代码被注入到 WebView 的当前页面并执行。这样,Java 代码就可以执行 WebView 中定义的 JavaScript 代码了。

在 Simple 例子中,传递了一个字符串。但是,当需要处理更复杂的结构时该怎么办呢?这就是 JSON 可派上用场的地方。清单 8 展示了 PerformComplexCalculation() 函数的调用,该函数参见 清单 6。

[b]清单 8. 通过传递一个 JSON 对象调用更复杂的函数[/b]

btnComplex.setOnClickListener(new OnClickListener()
{
public void onClick(View v) {
Log.i(tag,"onClick Complex");
// Perform action on click
try
{
String jsonText = "";

if (flipflop == 0)
{
jsonText = "{ \"operation\" : \"addarray\",\"arguments\" : [1,2,3,4,5,6,7,8,9,10]}";
flipflop = 1;
} else {
jsonText = "{ \"operation\" : \"multarray\",\"arguments\" : [1,2,3,4,5,6,7,8,9,10]}";
flipflop = 0;
}
Log.i(tag,"jsonText is [" + jsonText + "]" );
browser.loadUrl("javascript:PerformComplexCalculation(" + jsonText + ");");
}
catch (Exception e)
{
Log.e(tag,"Error ..." + e.getMessage());
}

}
});


研究一下 清单 6 中的 JavaScript 函数 PerformComplexCalculation。注意,传递进来的参数不是字符串,而是您自己创建的一个对象。

* operation - 要处理的函数或过程的名称
* arguments - 这是一个整数数组

对象只包含两个属性,但是完全可以更复杂,以满足更高的需求。在本例中,PerformComplexCalculation() JavaScript 函数支持两种不同的操作:addarray 和 multarray。当这些操作在调用时完成其工作时,通过调用函数 window.calc.setAnswer,将结果传递回 Java 代码。这里,您看到了 Java 和 JavaScript 代码之间的双向数据流。

在本例中,您传递了一个 JSON 对象,但是得到的一条经验是,在处理从 Java 代码返回来的 Java 字符串时,它有助于将它们转换成 JavaScript 字符串。这可以像本例中一样通过将值传递给 String 函数来做到:eval(String(formula));。

JavaScript eval() 函数使用 JavaScript 字符串。无需转换的话,eval 函数基本上不做任何事情。

对于一个稍微复杂一点的例子,鼓励您好好看一下 Dynamic 按钮在 WebView 中被选中时的代码段。

要完成代码例子,来看一下将一个字符串数组从 JavaScript 环境传递到 Java 环境。

[size=x-large]交换 JSON 对象[/size]

示例应用程序 (index.html) 中的 JavaScript 代码将本地函数调用记录到一个名为 cmdHistory 的页面级别数组中。每次调用函数时,您都将一个新条目添加到该数组中。例如,当 dynamicfunction() 被调用时,一个新的字符串被存储:cmdHistory[cmdHistory.length] = "PerformCompleCalculation-dynamic";。

关于此方法,没有什么特别的地方;它只是一个在页面级别收集使用数据的例子。也许该数据存储在 Android 应用程序的数据库中会有用。此数据如何回到 Java 代码呢?

要发送字符串对象数组,您调用 JSON.stringify 函数,将数组作为参数传递进来。根据需要,stringify 函数可以允许定制一个复杂对象的特定属性如何被格式化。关于这是如何完成的更多信息,可以参考 json.org 中的解释
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值