和Java交互

# 和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); ```