制限事項

Android 上のアプリケーションには、ビルド プロセス時に Java プロキシ型を生成することが求められるため、ランタイムですべてのコードを生成できるわけではありません。

デスクトップ Mono と比較して、Xamarin.Android には次の制限事項があります。

限定的な動的言語サポート

Android ランタイムでマネージド コードを呼び出す必要がある場合は、いかなるときも Android 呼び出し可能ラッパーが必要です。 Android 呼び出し可能ラッパーは、IL のスタティック分析に基づいてコンパイル時に生成されます。 この結果として、Java 型のサブクラス化が必要であるシナリオ (間接的なサブクラス化を含む) では、動的言語 (IronPython や IronRuby など) を使用できません。その理由は、コンパイル時にこれらの動的型を抽出して必要な Android 呼び出し可能ラッパーを生成する方法がないためです。

限定的な Java 生成サポート

Java コードでマネージド コードを呼び出すには、Android 呼び出し可能ラッパーを生成する必要があります。 "既定では"、Android 呼び出し可能ラッパーには、仮想 Java メソッド (つまり、RegisterAttribute を備える) のオーバーライドまたは Java インターフェイス メソッド (インターフェイスにも同様に Attributeがある) の実装を行うコンストラクターおよびメソッドの宣言のみが含まれます。

4.1 より前のリリースでは、追加のメソッドを宣言できませんでした。 リリース 4.1 では、Export および ExportField のカスタム属性を使用して、Android 呼び出し可能ラッパー内に Java メソッドおよびフィールドを宣言できます

不足しているコンストラクター

ExportAttribute を使用しない限り、コンストラクターは依然として扱いにくいままです。 Android 呼び出し可能ラッパー コンストラクターを生成するためのアルゴリズムは、次の場合に Java コンストラクターを出力するというものです。

  1. すべてのパラメーター型に対して Java マッピングがあります
  2. 基底クラスで同じコンストラクターを宣言します - こうすることが必要な理由は、Android 呼び出し可能ラッパーで、対応する基底クラス コンストラクターを呼び出す必要があるためです。既定の引数は使用できません (Java 内で使用する必要がある値を容易に特定する方法がないからです)。

たとえば、次の クラスについて考えてみましょう:

[Service]
class MyIntentService : IntentService {
    public MyIntentService (): base ("value")
    {
    }
}

これは完全に論理的であるように見えますが、"リリース ビルドで" 結果として得られる Android 呼び出し可能ラッパーには、既定のコンストラクターは含まれません。 その結果、このサービスを開始しようとしても (例: Context.StartService)、失敗します。

E/AndroidRuntime(31766): FATAL EXCEPTION: main
E/AndroidRuntime(31766): java.lang.RuntimeException: Unable to instantiate service example.MyIntentService: java.lang.InstantiationException: can't instantiate class example.MyIntentService; no empty constructor
E/AndroidRuntime(31766):        at android.app.ActivityThread.handleCreateService(ActivityThread.java:2347)
E/AndroidRuntime(31766):        at android.app.ActivityThread.access$1600(ActivityThread.java:130)
E/AndroidRuntime(31766):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1277)
E/AndroidRuntime(31766):        at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(31766):        at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(31766):        at android.app.ActivityThread.main(ActivityThread.java:4745)
E/AndroidRuntime(31766):        at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(31766):        at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(31766):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
E/AndroidRuntime(31766):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
E/AndroidRuntime(31766):        at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(31766): Caused by: java.lang.InstantiationException: can't instantiate class example.MyIntentService; no empty constructor
E/AndroidRuntime(31766):        at java.lang.Class.newInstanceImpl(Native Method)
E/AndroidRuntime(31766):        at java.lang.Class.newInstance(Class.java:1319)
E/AndroidRuntime(31766):        at android.app.ActivityThread.handleCreateService(ActivityThread.java:2344)
E/AndroidRuntime(31766):        ... 10 more

これを回避するには、既定のコンストラクターを宣言し、それを ExportAttribute で装飾し、ExportAttribute.SuperStringArgument を設定します。

[Service]
class MyIntentService : IntentService {
    [Export (SuperArgumentsString = "\"value\"")]
    public MyIntentService (): base("value")
    {
    }

    // ...
}

ジェネリック C# クラス

ジェネリック C# クラスは部分的にのみサポートされます。 次の制限があります。

  • ジェネリック型では、[Export][ExportField も使用できません。 それを試みると、XA4207 エラーが生成されます。

    public abstract class Parcelable<T> : Java.Lang.Object, IParcelable
    {
        // Invalid; generates XA4207
        [ExportField ("CREATOR")]
        public static IParcelableCreator CreateCreator ()
        {
            ...
    }
    
  • ジェネリック メソッドでは、[Export][ExportField] も使用できません。

    public class Example : Java.Lang.Object
    {
    
        // Invalid; generates XA4207
        [Export]
        public static void Method<T>(T value)
        {
            ...
        }
    }
    
  • [ExportField] を返すメソッド上で、void を使用することはできません。

    public class Example : Java.Lang.Object
    {
        // Invalid; generates XA4208
        [ExportField ("CREATOR")]
        public static void CreateSomething ()
        {
        }
    }
    
  • ジェネリック型のインスタンスを Java コードから作成することはできません。 これらは、マネージド コードからのみ安全に作成できます。

    [Activity (Label="Die!", MainLauncher=true)]
    public class BadGenericActivity<T> : Activity
    {
        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);
        }
    }
    

部分的な Java ジェネリックのサポート

Java ジェネリック バインディングのサポートは制限されています。 特に、別のジェネリック (インスタンス化されていない) クラスから派生したジェネリック インスタンス クラスのメンバーは、Java.Lang.Object として公開されたままになります。 たとえば、Android.Content.Intent.GetParcelableExtra メソッドからは Java.Lang.Object が返されます。 これは、Java ジェネリックが消去されたことが原因です。 この制限を適用しないクラスがいくつかありますが、それらは手動で調整します。