Limitações
Como os aplicativos no Android exigem a geração de tipos de proxy Java durante o processo de build, não é possível gerar todo o código em runtime.
Essas são as limitações do Xamarin.Android em comparação com o Mono da área de trabalho:
Suporte a linguagem dinâmica limitada
Os wrappers callable do Android são necessários sempre que o runtime do Android precisar invocar o código gerenciado. Os wrappers callable do Android são gerados em tempo de compilação, com base na análise estática da IL. O resultado líquido disso: você não pode usar linguagens dinâmicas (IronPython, IronRuby etc.) em qualquer cenário em que a subclasse de tipos Java seja necessária (incluindo subclasse indireta), pois não há como extrair esses tipos dinâmicos em tempo de compilação para gerar os wrappers callable do Android necessários.
Suporte limitado à geração java
Os Wrappers Callable do Android precisam ser gerados para que o código Java chame o código gerenciado. Por padrão, os wrappers callable do Android conterão apenas (determinados) construtores e métodos declarados que substituem um método Java virtual (ou seja, ele tem RegisterAttribute
) ou implementam um método de interface Java (a interface também tem Attribute
).
Antes da versão 4.1, nenhum método adicional poderia ser declarado. Com a versão 4.1, os Export
atributos personalizados e ExportField
podem ser usados para declarar métodos e campos Java dentro do Wrapper Callable do Android.
Construtores ausentes
Os construtores permanecem complicados ExportAttribute
, a menos que seja usado. O algoritmo para gerar construtores wrapper callable do Android é que um construtor Java será emitido se:
- Há um mapeamento java para todos os tipos de parâmetro
- A classe base declara o mesmo construtor – isso é necessário porque o wrapper callable do Android deve invocar o construtor de classe base correspondente; nenhum argumento padrão pode ser usado (pois não há uma maneira fácil de determinar quais valores devem ser usados no Java).
Por exemplo, considere a seguinte classe:
[Service]
class MyIntentService : IntentService {
public MyIntentService (): base ("value")
{
}
}
Embora isso pareça perfeitamente lógico, o wrapper callable do Android resultante em builds de versão não conterá um construtor padrão. Consequentemente, se você tentar iniciar esse serviço (por exemplo Context.StartService
, , ele falhará:
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
A solução alternativa é declarar um construtor padrão, adorná-lo com o ExportAttribute
e definir o ExportAttribute.SuperStringArgument
:
[Service]
class MyIntentService : IntentService {
[Export (SuperArgumentsString = "\"value\"")]
public MyIntentService (): base("value")
{
}
// ...
}
Classes C# genéricas
Classes C# genéricas têm suporte apenas parcialmente. As seguintes limitações existem:
Tipos genéricos podem não usar
[Export]
ou[ExportField
]. Tentar fazer isso gerará umXA4207
erro.public abstract class Parcelable<T> : Java.Lang.Object, IParcelable { // Invalid; generates XA4207 [ExportField ("CREATOR")] public static IParcelableCreator CreateCreator () { ... }
Métodos genéricos não podem usar
[Export]
ou[ExportField]
:public class Example : Java.Lang.Object { // Invalid; generates XA4207 [Export] public static void Method<T>(T value) { ... } }
[ExportField]
não pode ser usado em métodos que retornamvoid
:public class Example : Java.Lang.Object { // Invalid; generates XA4208 [ExportField ("CREATOR")] public static void CreateSomething () { } }
Instâncias de tipos genéricos não devem ser criadas a partir do código Java. Eles só podem ser criados com segurança a partir do código gerenciado:
[Activity (Label="Die!", MainLauncher=true)] public class BadGenericActivity<T> : Activity { protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); } }
Suporte parcial a genéricos Java
O suporte à associação de genéricos Java é limitado. Particularmente, os membros em uma classe de instância genérica derivada de outra classe genérica (não instanciada) são deixados expostos como Java.Lang.Object. Por exemplo, o método Android.Content.Intent.GetParcelableExtra retorna Java.Lang.Object. Isso ocorre devido a genéricos Java apagados. Temos algumas classes que não aplicam essa limitação, mas são ajustadas manualmente.