共用方式為


適用於 Xamarin.Android 的 Android 可呼叫包裝函式

每當 Android 執行時間叫用 Managed 程式代碼時,都需要 Android 可呼叫包裝函式 (ACWs)。 這些包裝函式是必要的,因為沒有任何方法在運行時間向 ART (Android 運行時間) 註冊類別。 (具體來說,是 Android 運行時間不支援 JNI DefineClass() 函 式。} 因此,Android 可呼叫包裝函式彌補了缺乏運行時間類型註冊支援。

每次 Android 程式代碼需要執行 virtual 或實作於 Managed 程式代碼中的 或 介面方法 overridden 時,Xamarin.Android 必須提供 Java Proxy,才能將此方法分派至適當的 Managed 類型。 這些 Java Proxy 類型是 Java 程式代碼,其基類和 Java 介面清單與 Managed 類型相同,實作相同的建構函式,並宣告任何覆寫的基類和介面方法。

Android 可呼叫包裝函式會在建置程式期間由monodroid.exe程式產生:系統會針對繼承 Java.Lang.Object 的所有類型產生這些包裝函式。

Android 可呼叫包裝函式命名

Android 可呼叫包裝函式的套件名稱是以所匯出類型之元件限定名稱的 MD5SUM 為基礎。 這種命名技術可讓不同的元件提供相同的完整類型名稱,而不會引入封裝錯誤。

由於這個 MD5SUM 命名配置,您無法依名稱直接存取類型。 例如,下列 adb 命令將無法運作,因為預設不會產生類型名稱 my.ActivityType

adb shell am start -n My.Package.Name/my.ActivityType

此外,如果您嘗試依名稱參考類型,您可能會看到如下的錯誤:

java.lang.ClassNotFoundException: Didn't find class "com.company.app.MainActivity"
on path: DexPathList[[zip file "/data/app/com.company.App-1.apk"] ...

如果您需要依名稱存取類型,您可以在屬性宣告中宣告該類型的名稱。 例如,以下是宣告具有完整名稱 My.ActivityType之活動的程式代碼:

namespace My {
    [Activity]
    public partial class ActivityType : Activity {
        /* ... */
    }
}

ActivityAttribute.Name屬性可以設定為明確宣告此活動的名稱:

namespace My {
    [Activity(Name="my.ActivityType")]
    public partial class ActivityType : Activity {
        /* ... */
    }
}

新增此屬性設定之後, my.ActivityType 可以從外部程式代碼和 adb 腳本依名稱存取。 Name屬性可以針對許多不同類型的設定,包括 ActivityApplicationServiceBroadcastReceiverContentProvider

以 MD5SUM 為基礎的 ACW 命名是在 Xamarin.Android 5.0 中引進的。 如需屬性命名的詳細資訊,請參閱 RegisterAttribute

實作介面

有時候您可能需要實作 Android 介面,例如 Android.Content.IComponentCallbacks。 由於所有 Android 類別和介面都會擴充 Android.Runtime.IJavaObject 介面,因此會發生問題:我們如何實 IJavaObject作 ?

上述問題已回答:所有 Android 類型都需要實 IJavaObject 作的原因,就是讓 Xamarin.Android 具有 Android 可呼叫包裝函式,以提供給 Android,也就是指定類型的 Java Proxy。 由於monodroid.exe只會尋找Java.Lang.Object子類別並Java.Lang.Object實作 IJavaObject,因此答案很明顯:子類別Java.Lang.Object

class MyComponentCallbacks : Java.Lang.Object, Android.Content.IComponentCallbacks {

    public void OnConfigurationChanged (Android.Content.Res.Configuration newConfig)
    {
        // implementation goes here...
    } 

    public void OnLowMemory ()
    {
        // implementation goes here...
    }
}

實作詳細資料

此頁面的其餘部分會提供實作詳細數據,但不會通知 變更(這裡只會顯示,因為開發人員會好奇發生了什麼事)。

例如,假設有下列 C# 來源:

using System;
using Android.App;
using Android.OS;

namespace Mono.Samples.HelloWorld
{
    public class HelloAndroid : Activity
    {
        protected override void OnCreate (Bundle savedInstanceState)
        {
            base.OnCreate (savedInstanceState);
            SetContentView (R.layout.main);
        }
    }
}

mandroid.exe程式會產生下列 Android 可呼叫包裝函式:

package mono.samples.helloWorld;

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

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

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

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

請注意,會保留基類,而且 native 會針對 Managed 程式代碼內覆寫的每個方法提供方法宣告。