2012-08-29 47 views
4

我創建了一個相當簡單的活動中爲單聲道Android項目:如何在Android應用程序中爲Android類調用Mono?

[Activity(Label = "AndroidApplication1", MainLauncher = true, Icon = "@drawable/icon")] 
public class Activity1 : Activity 
{ 
    private string value = "intitial"; 

    [Export] 
    public string GetString() 
    { 
     return value; 
    } 

    [Export] 
    public void SetString(string newValue) 
    { 
     value = newValue; 
    } 
} 

活動,只應作爲證明的概念,因此它的簡單性。現在,我希望能夠從「普通」的,基於Java的Android應用程序中調用方法GetString()。

Xamarin's docs,我已經閱讀了關於Java到託管互操作,這似乎正是我正在尋找。如果我的理解正確,當Mono for Android應用程序編譯時,它會生成被稱爲Android Callable Wrappers(ACW)的Java類。然後,我應該可以從基於Java的Android應用程序調用這些ACW上的方法。

問題是,我該如何從基於Java的Android應用程序中引用已編譯的Mono for Android應用程序(apk文件)?

這就是我現在卡住的地方,無法找到任何具體的例子。在SO(this onethis one)和一些博文中也有類似的問題,但他們只是歸結爲「使用ACW」。 但究竟如何?也許我錯過了一些很明顯的東西,不是Android的傢伙。

我已經試過是動態加載DEX文件,我從我的單猛拉爲Android APK 。我只是把它放在存儲卡上,然後嘗試從基於Java的Android應用程序中使用DexClassLoader加載它(我按照此blog post)。該ACW類被發現,但是當我試圖創建它的實例,我得到了以下錯誤:

No implementation found for native Lmno/android/Runtime;.register (Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)

我想,我必須以某種方式包括單爲Android運行在基於Java的應用程序,但我有不知道如何。

編輯: 這是我試圖與加載DEX代碼:

DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(), 
    optimizedDexOutputPath.getAbsolutePath(), 
    null, 
    getClassLoader()); 

try { 
    Class<?> classActivity1 = cl.loadClass("androidapplication1.Activity1"); 

    // the following line throws the exception 
    Object a = classActivity1.newInstance(); 

    Method getStringMethod = classActivity1.getMethod("GetString"); 
    Object result = getStringMethod.invoke(angel); 

    result = null; 
} catch (Exception e) { 
    e.printStackTrace(); 
} 

EDIT2: 現在我讀here,它應該是可以直接啓動活動用Java從Mono for Android中編寫。我還不清楚如何從Java引用Android的Mono,並且Googling不會產生相關的命中。真的難倒了。

回答

4

如果我正確理解你想要做的事情,這是不可能的。正如您得到的錯誤消息所暗示的,Mono for Android應用程序中的Activity依賴於Mono運行時才能正常運行。在這種情況下,可調用包裝器本身並無用處,因爲它只是調用Mono運行時的瘦Java包裝器類。如果您在構建項目後查看obj/Debug/android/src文件夾,您實際上可以自己查看生成的可調用包裝器。例如:

package androidapplication9; 


public class Activity1 
    extends android.app.Activity 
    implements 
     mono.android.IGCUserPeer 
{ 
    static final String __md_methods; 
    static { 
     __md_methods = 
      "n_onCreate:(Landroid/os/Bundle;)V:GetOnCreate_Landroid_os_Bundle_Handler\n" + 
      ""; 
     mono.android.Runtime.register ("AndroidApplication9.Activity1, AndroidApplication9, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", Activity1.class, __md_methods); 
    } 


    public Activity1() 
    { 
     super(); 
     if (getClass() == Activity1.class) 
      mono.android.TypeManager.Activate ("AndroidApplication9.Activity1, AndroidApplication9, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "", this, new java.lang.Object[] { }); 
    } 


    public void onCreate (android.os.Bundle p0) 
    { 
     n_onCreate (p0); 
    } 

    private native void n_onCreate (android.os.Bundle p0); 

    java.util.ArrayList refList; 
    public void monodroidAddReference (java.lang.Object obj) 
    { 
     if (refList == null) 
      refList = new java.util.ArrayList(); 
     refList.add (obj); 
    } 

    public void monodroidClearReferences() 
    { 
     if (refList != null) 
      refList.clear(); 
    } 
} 

這就是說,由於Android的工作方式,你可以有一個Java應用程序啓動以單定義Android應用程序以同樣的方式活動,你會開始外部Java活動。這當然依賴於兩個正在安裝的應用程序,但會導致Mono for Android應用程序和Mono運行時實際啓動運行該活動。

編輯

更新爲您解答您的評論中提出的問題。 ExportAttribute基本上只是給你一些關於ACW如何生成的控制權,允許你指定一個特定的方法或字段應該存在於ACW中,以及它應該具有什麼名稱。當您想在佈局中使用諸如android:onClick屬性之類的東西時,這會很有用,例如,默認情況下,ACW不包含您想要引用的方法。

由於Mono運行時不存在,所以在Mono for Android應用程序的上下文之外,無法從ACW中獲得太多用處。用C#編寫的代碼是在Mono運行時之上執行的,並且在編譯期間不會在後臺翻譯成Java或類似的東西。在運行時,有兩個並行的運行時間,Dalvik(Android的運行時)和Mono,可調用的包裝器在那裏允許二者來回通信。因此,即使是Mono for Android類庫仍然依賴於Mono運行時,所以不能獨立於運行時使用它。

下圖顯示了架構是什麼樣子,以及運行時如何相互關聯的:

Mono for Android architecture

希望這有助於清楚的事情了!

+0

非常感謝您的回答,最終能與您合作!你在說什麼很有道理,但是那些Xamarin文檔的目的是什麼呢?我什麼時候可以使用ACW和'Export'屬性?也許最重要的是,是否有任何方法可以使Java應用程序與Mono for Android類「交談」,而無需安裝兩個單獨的應用程序 - 即類似於安裝Mono for Android庫並僅從Java應用程序引用它?如果你能爲我澄清一點,我會很感激。 –

相關問題