和Java交互
Rhino提供了非常方便地和Java交互的能力。
liveConnect:与JavaScript的Java通信
Rhino允许您从JavaScript中创建Java类并调用Java方法。例如:
let builder = new java.lang.Builder();
builder.append('test');
builder.append(1);
console.log(builder.toString());
访问JavaBean属性
Java类可以使用getter和Setter方法定义JavaBean属性。例如,以下类定义了两个属性:
public class Me {
public int getAge() \{ return mAge; \}
public void setAge(int anAge) \{ mAge = anAge; \}
public String getSex() \{ return "male"; \}
private int mAge;
};
定义的两个属性是 age_和_sex。 _sex_属性是只读的:它没有Setter。
使用Rhino我们可以访问Bean属性,就像它们一样的JavaScript属性。我们也可以继续调用定义属性的方法。
let me = new Me();
console.log(me.sex);
me.age = 33;
console.log(me.age);
console.log(me.getAge());
由于_sex_属性是只读的,因此我们不允许写入它。
导入Java类和包
上面我们看到了importPackage函数的使用来从特定的Java包导入所有类。还有importClass,它导入单个类。
你可以直接使用android.view.View
来表示Android中的View类,默认支持的顶级包名前缀为com
, android
, java
, org
,对于其他包名,需要使用Packages
对象,比如Packages.javax.xml.xpath.XPath
或Packages["javax.xml.xpath.XPath"]
。
也可以使用importClass
或importPackage
函数来导入Java/Android中的包名或类,比如:
importClass("android.view.KeyEvent");
// 或者
let KeyEvent = android.view.KeyEvent;
// 或者
importPackage("android.view");
扩展Java类并使用JavaScript实现Java接口
例如为某个UI中的控件设置点击监听OnClickListener:
"ui";
$ui.layout(
<frame>
<button id="btn" text="BUTTON"/>
</frame>
);
let listener = new android.view.View.OnClickListener(function(view) {
console.log("clicked");
});
$ui.btn.setOnClickListener(listener);
当我们键入new android.view.View.OnClickListener
时,rhino实际上创建了一个新的Java类,它实现了OnClickListener并将从该类转发给JavaScript对象的调用。
Rhino也允许将JavaScript函数直接传递给Java方法,如果相应的参数是Java接口,它具有单个方法或其所有方法具有相同数量的参数,相应的参数具有相同类型的参数。例如:
$ui.btn.setOnClickListener(function(view) {
console.log("clicked");
});
若Java接口有多个方法,则可以传入一个JavaScript对象来实现他,比如对于Java接口:
/**
* Interface definition for a callback to be invoked when this view is attached
* or detached from its window.
*/
public interface OnAttachStateChangeListener {
/**
* Called when the view is attached to a window.
* @param v The view that was attached
*/
public void onViewAttachedToWindow(View v);
/**
* Called when the view is detached from a window.
* @param v The view that was detached
*/
public void onViewDetachedFromWindow(View v);
}
我们可以在JavaScript中这样实现:
let listener = new android.view.View.OnAttachStateChangeListener({
onViewAttachedToWindow: function(view) {
console.log('attached');
},
onViewDetachedFromWindow: function(view) {
console.log('detached');
}
});
$ui.btn.addOnAttachStateChangeListener(listener);
JavaAdapter构造函数
使用JavaAdapter也可以用于实现接口,同时可以用于继承普通类或抽象类。他的原理是动态生成一个类。
let listener = new JavaAdapter(android.view.View.OnAttachStateChangeListener, {
onViewAttachedToWindow: function(view) {
console.log('attached');
},
onViewDetachedFromWindow: function(view) {
console.log('detached');
}
});
如果我们想实现多个接口,则:
let listener = new JavaAdapter(android.view.View.OnAttachStateChangeListener, java.lang.Runnable, {
onViewAttachedToWindow: function(view) {
console.log('attached');
},
onViewDetachedFromWindow: function(view) {
console.log('detached');
},
run: function() {
console.log('run');
}
});
一般来说,语法是:
new JavaAdapter(java-class, [java-class,...],javascript-object, [args...])
最多一个java-class是java类,剩下的java-class参数是接口。结果将是继承指定的Java类并实现所有的Java接口,并将任何调用转发给javascript-object的方法。args参数用于指定构造Java类的构造函数。
比如继承View,重写onDraw函数:
"ui";
$ui.layout(
<vertical>
<frame id="container"/>
</vertical>
);
let paint = new Paint();
let view = new JavaAdapter(android.view.View, {
onDraw: function (canvas) {
// 调用父类View的onDraw
this.super$onDraw(canvas);
canvas.drawRect(500, 500, 1000, 1000, paint);
},
// activity为android.view.View的构造函数参数
}, activity);
$ui.container.addView(view);