Obálky volatelné pro Android pro Xamarin.Android
Při vyvolání spravovaného kódu modul runtime Androidu se vyžadují obálky s možností volání Androidu (ACWs). Tyto obálky jsou vyžadovány, protože neexistuje způsob, jak za běhu zaregistrovat třídy v modulu RUNTIME (Android Runtime). (Konkrétně se jedná o Modul runtime Androidu nepodporuje funkci JNI DefineClass().} Obálky volatelné pro Android se tak tvoří kvůli nedostatku podpory registrace typu modulu runtime.
Pokaždé, když kód Androidu potřebuje spustit metodu nebo metodu virtual
rozhraní, která je overridden
nebo implementovaná ve spravovaném kódu, musí Xamarin.Android poskytnout proxy jazyka Java, aby byla tato metoda odeslána do příslušného spravovaného typu. Tyto typy proxy serverů Java jsou kód Java, který má "stejnou" základní třídu a seznam rozhraní Java jako spravovaný typ, implementuje stejné konstruktory a deklaruje všechny přepsané základní třídy a metody rozhraní.
Obálky volatelné pro Android jsou generovány programem monodroid.exe během procesu sestavení: jsou generovány pro všechny typy, které (přímo nebo nepřímo) dědí Java.Lang.Object.
Pojmenování volatelného obálky pro Android
Názvy balíčků pro obálky volatelné pro Android jsou založeny na MD5SUM sestavení kvalifikovaný název typu, který se exportuje. Tato technika pojmenování umožňuje, aby byl stejný plně kvalifikovaný název typu zpřístupněn různými sestaveními bez zavedení chyby balení.
Kvůli tomuto schématu pojmenování MD5SUM nemůžete přímo přistupovat k typům podle názvu. Například následující adb
příkaz nebude fungovat, protože název my.ActivityType
typu není ve výchozím nastavení generován:
adb shell am start -n My.Package.Name/my.ActivityType
Pokud se pokusíte odkazovat na typ podle názvu, můžou se také zobrazit chyby podobné následujícímu:
java.lang.ClassNotFoundException: Didn't find class "com.company.app.MainActivity"
on path: DexPathList[[zip file "/data/app/com.company.App-1.apk"] ...
Pokud potřebujete přístup k typům podle názvu, můžete deklarovat název pro tento typ v deklaraci atributu. Tady je například kód, který deklaruje aktivitu s plně kvalifikovaným názvem My.ActivityType
:
namespace My {
[Activity]
public partial class ActivityType : Activity {
/* ... */
}
}
Vlastnost ActivityAttribute.Name
lze nastavit tak, aby explicitně deklaruje název této aktivity:
namespace My {
[Activity(Name="my.ActivityType")]
public partial class ActivityType : Activity {
/* ... */
}
}
Po přidání my.ActivityType
tohoto nastavení vlastnosti je možné k němu přistupovat pomocí názvu z externího kódu a ze adb
skriptů. Atribut Name
lze nastavit pro mnoho různých typů, včetně Activity
, Application
Service
, , BroadcastReceiver
a ContentProvider
:
- ActivityAttribute.Name
- ApplicationAttribute.Name
- ServiceAttribute.Name
- BroadcastReceiverAttribute.Name
- ContentProviderAttribute.Name
Pojmenování ACW založené na MD5SUM bylo zavedeno v Xamarin.Android 5.0. Další informace o pojmenování atributů naleznete v tématu RegisterAttribute.
Implementace rozhraní
Někdy může být potřeba implementovat rozhraní Androidu, například Android.Content.IComponentCallbacks.
Vzhledem k tomu, že všechny třídy a rozhraní Androidu rozšiřují rozhraní Android.Runtime.IJavaObject , vyvstává otázka: jak implementujeme IJavaObject
?
Na otázku jsme odpověděli výše: důvodem, proč je potřeba implementovat IJavaObject
všechny typy Androidu, je, aby Xamarin.Android měl obálku s možností volání pro Android, tj. proxy Java pro daný typ. Vzhledem k tomu , monodroid.exe hledá Java.Lang.Object
pouze podtřídy a Java.Lang.Object
implementuje IJavaObject
, odpověď je zřejmé: podtřída 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...
}
}
Podrobnosti implementace
Zbývající část této stránky obsahuje podrobnosti implementace, které se mohou bez předchozího upozornění změnit (a jsou zde uvedeny pouze proto, že vývojáři budou zvědaví na to, co se děje).
Například vzhledem k následujícímu zdroji jazyka 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);
}
}
}
Program mandroid.exe vygeneruje následující obálku pro Android Callable Wrapper:
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);
}
Všimněte si, že základní třída je zachována a native
deklarace metod jsou k dispozici pro každou metodu, která je přepsána v rámci spravovaného kódu.