var button1 = findview(R.id('button1'));
button1.setOnClickListener(function(view, methodName)
{
if (methodName == "onClick") {
log("MyScript", "clicked");
} });
當然不是很滿意, "if(methodName == "onClick")"這樣的寫法太醜了啦!
所以這次的目標是:
button1.onclick = function(view) {
log("MyScript", "clicked");
alert('Hi there!');
};
這樣比較像印象中javascript的寫法
為了達到這目的, 必須在View中加入onclick這個property, 但原本View class(Java)並沒這東西, 如何將它包裝出來?
Rhino對於Javascript使用原生的java objects並不是直接使用, 還是有透過一層包裝, 因此這就是要做出這個property的路了, 包裝的點在於WrapFactory, 而原生的Java object會被包裝長NativeJavaObject
而Rhino允許我們用自己的WrapFactory取代原本的, 像是這樣:
jsContext.setWrapFactory(new AndroidWrapFactory());
因此我們會需要自己實作這一個AndroidWrapFactory, 把原本的View改用不同的包裝, 而非原本的NativeJavaObject, 基本上只需要實作wrapAsJavaObject即可:
這邊用了一個新實作的ViewWrapper來取代NativeJavaObject
本來我的打算是繼承自NativeJavaObject, 然後再加入自己的東西, 不過後來發現這樣的作法總會在"put"時出差錯, 原因是NativeJavaObject是沒辦法加入新的member了(其實這說法有點問題, 應該是只要設prototype給它的話還是可以), 加上一些比較實用的function是定義在ScriptableObject的裡面, 因此, 我最後採用ScriptableObject來包裝
但要如何在ScriptableObject裡面實現像NativeJavaObject那樣可以直接叫用原本的Java class裡面的member呢?這部份不用自己實作, 只要把原本的NativeJavaObject當做這新的ViewWrapper的prototype就好了, 所以這邊constructor呼叫的super contructor是:
public ScriptableObject(Scriptable scope, Scriptable prototype)
===> super(scope, new NativeJavaObject(scope, javaObject, staticType));
defineProperty這包裝是從ScritableObject那邊改寫其中一個過來的, 主要是用來讓我們可以把這些"onlick","onlongclick"包裝成property, 在ViewWrapper可以實作getter和setter, 為了避免名稱上的混淆, 所以把getter的prefix定義成"jsget"而setter是"jsset"
在onlick的setter中, 除了將function object存起來外, 還直接對原本包裝的View設一個OnClickListener, 動作則是執行這個Function object
最後, 前面的範例裡面有一個"alert('Hi! there')", 因此為了"alert()"多實作一個Alert.java出來(跟上面的無關啦), 這是source:
接下來的目標,
- 包裝一個實際真的可以拿來開發的package, release 0.1 alpha
- 實作XmlHttpRequest
- Adapter & AdapterView, Service & Provider
沒有留言:
張貼留言