適用於 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
屬性可以針對許多不同類型的設定,包括 Activity
、Application
、Service
、 BroadcastReceiver
和 ContentProvider
:
- ActivityAttribute.Name
- ApplicationAttribute.Name
- ServiceAttribute.Name
- BroadcastReceiverAttribute.Name
- ContentProviderAttribute.Name
以 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 程式代碼內覆寫的每個方法提供方法宣告。