体系结构Architecture

Mono 的执行环境中运行 Xamarin.Android 应用程序。Xamarin.Android applications run within the Mono execution environment. 此执行环境运行的并行与 Android 运行时 (艺术) 虚拟机。This execution environment runs side-by-side with the Android Runtime (ART) virtual machine. 这两个运行时环境在 Linux 内核顶层运行,并公开到用户代码,允许开发人员访问基础系统的各种 Api。Both runtime environments run on top of the Linux kernel and expose various APIs to the user code that allows developers to access the underlying system. Mono 运行时是用 C 语言编写的。The Mono runtime is written in the C language.

你可以使用系统System.IOSystem.Net和其余部分的.net 类库以访问基础 Linux 操作系统功能。You can be using the System, System.IO, System.Net and the rest of the .NET class libraries to access the underlying Linux operating system facilities.

在 Android 上,大部分系统机制,例如音频、 图形、 OpenGL 和电话服务不可用直接到本机应用程序,它们仅公开通过 Android 运行时 Java Api 中的一个驻留Java。 *命名空间或Android。 * 命名空间。On Android, most of the system facilities like Audio, Graphics, OpenGL and Telephony are not available directly to native applications, they are only exposed through the Android Runtime Java APIs residing in one of the Java.* namespaces or the Android.* namespaces. 体系结构是大致如下:The architecture is roughly like this:

关系图的 Mono 和画内核上方和下方.NET/Java + 绑定Diagram of Mono and ART above the kernel and below .NET/Java + bindings

Xamarin.Android 开发人员访问操作系统通过调入他们知道的.NET Api (用于低级别的访问权限) 或使用 Android 的 Java api 公开的架起了桥梁的命名空间中公开的类中的各种功能Android 运行时。Xamarin.Android developers access the various features in the operating system either by calling into .NET APIs that they know (for low-level access) or using the classes exposed in the Android namespaces which provides a bridge to the Java APIs that are exposed by the Android Runtime.

Android 类如何与 Android 运行时类进行通信的详细信息请参阅API 设计文档。For more information on how the Android classes communicate with the Android Runtime classes see the API Design document.

应用程序包Application Packages

Android 应用程序包是包含 ZIP 容器 .apk文件扩展名。Android application packages are ZIP containers with a .apk file extension. Xamarin.Android 应用程序包具有相同的结构和布局作为常规 Android 包,增加了以下信息:Xamarin.Android application packages have the same structure and layout as normal Android packages, with the following additions:

  • (包含 IL) 的应用程序程序集都存储内未压缩程序集文件夹。The application assemblies (containing IL) are stored uncompressed within the assemblies folder. 在过程中启动版本中的生成 .apkmmap() ed 到过程和程序集是从内存中加载。During process startup in Release builds the .apk is mmap() ed into the process and the assemblies are loaded from memory. 这将允许更快的应用程序启动,因为程序集不需要在执行之前提取。This permits faster app startup, as assemblies do not need to be extracted prior to execution.

  • 注意: 程序集位置信息,例如Assembly.LocationAssembly.CodeBase 不能依赖发布版本中。Note: Assembly location information such as Assembly.Location and Assembly.CodeBase cannot be relied upon in Release builds. 为不同的文件系统条目不存在,并且必须没有可用的位置。They do not exist as distinct filesystem entries, and they have no usable location.

  • 包含 Mono 运行时本机库中有 .apkNative libraries containing the Mono runtime are present within the .apk . Xamarin.Android 应用程序必须包含本机库所需目标 Android 体系结构,例如armeabiarmeabi-v7ax86A Xamarin.Android application must contain native libraries for the desired/targeted Android architectures, e.g. armeabi , armeabi-v7a , x86 . Xamarin.Android 应用程序不能在平台上运行,除非它包含相应的运行时库。Xamarin.Android applications cannot run on a platform unless it contains the appropriate runtime libraries.

Xamarin.Android 应用程序还包含Android 可调用包装器为允许 Android 来调入托管代码。Xamarin.Android applications also contain Android Callable Wrappers to allow Android to call into managed code.

Android 可调用包装器Android Callable Wrappers

  • Android 可调用包装器JNI桥用于 Android 运行时需要调用托管的代码的任何时间。Android callable wrappers are a JNI bridge which are used any time the Android runtime needs to invoke managed code. Android 可调用包装器是如何虚拟方法可以重写并且可以实现 Java 接口。Android callable wrappers are how virtual methods can be overridden and Java interfaces can be implemented. 请参阅Java 集成概述文档的详细信息。See the Java Integration Overview doc for more.

托管的可调用包装器Managed Callable Wrappers

托管的可调用包装器是用于托管的代码需要调用 Android 代码,并提供对重写虚拟方法和实现 Java 接口支持的任何时间的 JNI 桥梁。Managed callable wrappers are a JNI bridge which are used any time managed code needs to invoke Android code and provide support for overriding virtual methods and implementing Java interfaces. 整个Android。 * 和相关命名空间都是通过生成的托管可调用包装.jar 绑定The entire Android.* and related namespaces are managed callable wrappers generated via .jar binding. 托管的可调用包装器负责托管和 Android 的类型之间进行转换和调用 JNI 通过基础的 Android 平台方法。Managed callable wrappers are responsible for converting between managed and Android types and invoking the underlying Android platform methods via JNI.

每个 Java 全局引用,该类可通过创建托管的可调用包装器持有Android.Runtime.IJavaObject.Handle属性。Each created managed callable wrapper holds a Java global reference, which is accessible through the Android.Runtime.IJavaObject.Handle property. 全局引用用于提供 Java 实例和托管的实例之间的映射。Global references are used to provide the mapping between Java instances and managed instances. 全局引用是一种有限的资源: 仿真程序使得仅 2000年全局引用存在一次,而大多数硬件允许超过 52,000 全局引用,以同时存在。Global references are a limited resource: emulators allow only 2000 global references to exist at a time, while most hardware allows over 52,000 global references to exist at a time.

若要跟踪时创建和销毁全局引用,可以设置debug.mono.log系统属性以包含grefTo track when global references are created and destroyed, you can set the debug.mono.log system property to contain gref.

全局引用可以显式释放通过调用Java.Lang.Object.Dispose()上托管的可调用包装器。Global references can be explicitly freed by calling Java.Lang.Object.Dispose() on the managed callable wrapper. 这将删除 Java 实例和托管的实例之间的映射,并允许收集的 Java 实例。This will remove the mapping between the Java instance and the managed instance and allow the Java instance to be collected. 如果从托管代码重新访问 Java 实例,将为其创建新的托管可调用包装器。If the Java instance is re-accessed from managed code, a new managed callable wrapper will be created for it.

当释放的托管可调用包装器,如果该实例可以在无意中线程之间共享,以释放该实例将会影响任何其他线程的引用,因此必须小心谨慎。Care must be exercised when disposing of Managed Callable Wrappers if the instance can be inadvertently shared between threads, as disposing the instance will impact references from any other threads. 为了最大的安全,仅Dispose()的实例都通过已分配new方法从在知道始终分配新实例并将可能不缓存的实例会导致意外实例线程间共享。For maximum safety, only Dispose() of instances which have been allocated via new or from methods which you know always allocate new instances and not cached instances which may cause accidental instance sharing between threads.

托管可调用包装器子类Managed Callable Wrapper Subclasses

托管的可调用包装器子类是可能所在的"有意义"的所有特定于应用程序逻辑。Managed callable wrapper subclasses are where all the "interesting" application-specific logic may live. 其中包括自定义Android.App.Activity子类 (如Activity1默认项目模板中的类型)。These include custom Android.App.Activity subclasses (such as the Activity1 type in the default project template). (具体而言,这些是任何Java.Lang.Object来执行此操作的子类包含RegisterAttribute自定义特性或RegisterAttribute.DoNotGenerateAcwfalse,这是默认设置。)(Specifically, these are any Java.Lang.Object subclasses which do not contain a RegisterAttribute custom attribute or RegisterAttribute.DoNotGenerateAcw is false, which is the default.)

如管理托管的可调用包装可调用包装器子类还包含全局引用,可通过访问Java.Lang.Object.Handle属性。Like managed callable wrappers, managed callable wrapper subclasses also contain a global reference, accessible through the Java.Lang.Object.Handle property. 就像与托管的可调用包装器,通过调用全局引用可以显式释放操作Java.Lang.Object.Dispose()Just as with managed callable wrappers, global references can be explicitly freed by calling Java.Lang.Object.Dispose(). 与托管的可调用包装器,不同谨慎应为释放的这种情况下前, 采取dispose () 定义是该实例将中断 Java 实例之间的映射 (的实例Android 可调用包装器) 和托管的实例。Unlike managed callable wrappers, great care should be taken before disposing of such instances, as Dispose()-ing of the instance will break the mapping between the Java instance (an instance of an Android Callable Wrapper) and the managed instance.

Java 激活Java Activation

Android 可调用包装器(ACW) 创建从 Java,ACW 构造函数将导致相应 C# 要调用构造函数。When an Android Callable Wrapper (ACW) is created from Java, the ACW constructor will cause the corresponding C# constructor to be invoked. 例如,对于 ACW MainActivity将包含默认构造函数将调用MainActivity的默认构造函数。For example, the ACW for MainActivity will contain a default constructor which will invoke MainActivity's default constructor. (这是通过TypeManager.Activate() ACW 构造函数内调用。)(This is done through the TypeManager.Activate() call within the ACW constructors.)

没有结果的一个其他构造函数签名: (IntPtr,JniHandleOwnership) 构造函数。There is one other constructor signature of consequence: the (IntPtr, JniHandleOwnership) constructor. (IntPtr,JniHandleOwnership) 每当 Java 对象公开给托管代码和托管的可调用包装器需要构造管理 JNI 句柄调用构造函数。The (IntPtr, JniHandleOwnership) constructor is invoked whenever a Java object is exposed to managed code and a Managed Callable Wrapper needs to be constructed to manage the JNI handle. 这通常是自动完成。This is usually done automatically.

有两种情况下, (IntPtr,JniHandleOwnership) 上托管的可调用包装器子类必须手动提供构造函数:There are two scenarios in which the (IntPtr, JniHandleOwnership) constructor must be manually provided on a Managed Callable Wrapper subclass:

  1. Android.App.Application子类化。Android.App.Application is subclassed. 应用程序是特殊; 默认值应用程序构造函数将永远不会调用,和(IntPtr,JniHandleOwnership) 必须改为提供构造函数.Application is special; the default Applicaton constructor will never be invoked, and the (IntPtr, JniHandleOwnership) constructor must instead be provided.

  2. 从基类构造函数的虚拟方法调用。Virtual method invocation from a base class constructor.

请注意,(2) 是一个有漏洞的抽象。Note that (2) is a leaky abstraction. 在 Java 中,与 C# 中,从一个构造函数调用虚拟方法始终调用派生程度最高的方法实现。In Java, as in C#, calls to virtual methods from a constructor always invoke the most derived method implementation. 例如, TextView (上下文,AttributeSet,int) 构造函数调用虚拟方法TextView.getDefaultMovementMethod(),该绑定为TextView.DefaultMovementMethod 属性For example, the TextView(Context, AttributeSet, int) constructor invokes the virtual method TextView.getDefaultMovementMethod(), which is bound as the TextView.DefaultMovementMethod property. 因此,如果某种LogTextBox为 (1) 已子类 TextView,(2)重写 TextView.DefaultMovementMethod,和 (3)激活它的实例类的 XML,通过重写DefaultMovementMethod之前 ACW 构造函数有机会执行时,它会发生之前将调用属性C#机会到构造函数执行。Thus, if a type LogTextBox were to (1) subclass TextView, (2) override TextView.DefaultMovementMethod, and (3) activate an instance of that class via XML, the overridden DefaultMovementMethod property would be invoked before the ACW constructor had a chance to execute, and it would occur before the C# constructor had a chance to execute.

这通过实例化实例 LogTextBox 支持通过LogTextView (IntPtr,JniHandleOwnership)构造函数时 ACW LogTextBox 实例首次进入托管代码中,然后再调用(上下文,IAttributeSet,int) LogTextBox构造函数同一个实例上ACW 构造函数执行时。This is supported by instantiating an instance LogTextBox through the LogTextView(IntPtr, JniHandleOwnership) constructor when the ACW LogTextBox instance first enters managed code, and then invoking the LogTextBox(Context, IAttributeSet, int) constructor on the same instance when the ACW constructor executes.

事件的发生顺序:Order of events:

  1. 布局 XML 加载到ContentViewLayout XML is loaded into a ContentView.

  2. Android 实例化布局的对象图,并实例化的实例monodroid.apidemo.LogTextBox ,为 ACW LogTextBoxAndroid instantiates the Layout object graph, and instantiates an instance of monodroid.apidemo.LogTextBox , the ACW for LogTextBox .

  3. Monodroid.apidemo.LogTextBox构造函数执行android.widget.TextView构造函数。The monodroid.apidemo.LogTextBox constructor executes the android.widget.TextView constructor.

  4. TextView构造函数调用monodroid.apidemo.LogTextBox.getDefaultMovementMethod()The TextView constructor invokes monodroid.apidemo.LogTextBox.getDefaultMovementMethod() .

  5. monodroid.apidemo.LogTextBox.getDefaultMovementMethod() 调用LogTextBox.n_getDefaultMovementMethod() ,这样就可调用TextView.n_GetDefaultMovementMethod() ,这样就可调用Java.Lang.Object.GetObject<TextView> (处理 JniHandleOwnership.DoNotTransfer)monodroid.apidemo.LogTextBox.getDefaultMovementMethod() invokes LogTextBox.n_getDefaultMovementMethod() , which invokes TextView.n_GetDefaultMovementMethod() , which invokes Java.Lang.Object.GetObject<TextView> (handle, JniHandleOwnership.DoNotTransfer) .

  6. Java.Lang.Object.GetObject<TextView>() 检查,以查看是否已经存在相应的 C# 实例处理Java.Lang.Object.GetObject<TextView>() checks to see if there is already a corresponding C# instance for handle . 如果不存在,则返回它。If there is, it is returned. 在此方案中,不存在,这样Object.GetObject<T>() 必须先创建一个。In this scenario, there isn't, so Object.GetObject<T>() must create one.

  7. Object.GetObject<T>() 寻找LogTextBox (IntPtr,JniHandleOwneship) 构造函数,对其进行调用,之间创建映射处理和创建的实例,并返回所创建的实例。Object.GetObject<T>() looks for the LogTextBox(IntPtr, JniHandleOwneship) constructor, invokes it, creates a mapping between handle and the created instance, and returns the created instance.

  8. TextView.n_GetDefaultMovementMethod() 调用LogTextBox.DefaultMovementMethod属性 getter。TextView.n_GetDefaultMovementMethod() invokes the LogTextBox.DefaultMovementMethod property getter.

  9. 控制权将返回给android.widget.TextView构造函数,完成执行。Control returns to the android.widget.TextView constructor, which finishes execution.

  10. Monodroid.apidemo.LogTextBox构造函数执行时,调用TypeManager.Activate()The monodroid.apidemo.LogTextBox constructor executes, invoking TypeManager.Activate() .

  11. LogTextBox (上下文,IAttributeSet,int) 构造函数执行 (7) 中创建的同一实例上The LogTextBox(Context, IAttributeSet, int) constructor executes on the same instance created in (7) .

  12. 如果 (IntPtr,JniHandleOwnership) 找不到构造函数,则将引发 System.MissingMethodException](xref:System.MissingMethodException)。If the (IntPtr, JniHandleOwnership) constructor cannot be found, then a System.MissingMethodException](xref:System.MissingMethodException) will be thrown.

过早 dispose () 调用Premature Dispose() Calls

没有 JNI 句柄和对应的 C# 实例之间的映射。There is a mapping between a JNI handle and the corresponding C# instance. Java.Lang.Object.Dispose() 将中断此映射。Java.Lang.Object.Dispose() breaks this mapping. 如果映射已中断后,JNI 句柄将进入托管的代码,它类似于 Java 激活并 (IntPtr,JniHandleOwnership) 构造函数将检查并调用。If a JNI handle enters managed code after the mapping has been broken, it looks like Java Activation, and the (IntPtr, JniHandleOwnership) constructor will be checked for and invoked. 如果构造函数不存在,将引发异常。If the constructor doesn't exist, then an exception will be thrown.

例如,给定以下托管可调用 Wraper 子类:For example, given the following Managed Callable Wraper subclass:

class ManagedValue : Java.Lang.Object {

    public string Value {get; private set;}

    public ManagedValue (string value)
    {
        Value = value;
    }

    public override string ToString ()
    {
        return string.Format ("[Managed: Value={0}]", Value);
    }
}

如果我们创建一个实例,dispose (),并且会导致托管可调用包装器以重新创建:If we create an instance, Dispose() of it, and cause the Managed Callable Wrapper to be re-created:

var list = new JavaList<IJavaObject>();
list.Add (new ManagedValue ("value"));
list [0].Dispose ();
Console.WriteLine (list [0].ToString ());

该程序会死亡:The program will die:

E/mono    ( 2906): Unhandled Exception: System.NotSupportedException: Unable to activate instance of type Scratch.PrematureDispose.ManagedValue from native handle 4051c8c8 --->
System.MissingMethodException: No constructor found for Scratch.PrematureDispose.ManagedValue::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership)
E/mono    ( 2906):   at Java.Interop.TypeManager.CreateProxy (System.Type type, IntPtr handle, JniHandleOwnership transfer) [0x00000] in <filename unknown>:0
E/mono    ( 2906):   at Java.Interop.TypeManager.CreateInstance (IntPtr handle, JniHandleOwnership transfer, System.Type targetType) [0x00000] in <filename unknown>:0
E/mono    ( 2906):   --- End of inner exception stack trace ---
E/mono    ( 2906):   at Java.Interop.TypeManager.CreateInstance (IntPtr handle, JniHandleOwnership transfer, System.Type targetType) [0x00000] in <filename unknown>:0
E/mono    ( 2906):   at Java.Lang.Object.GetObject (IntPtr handle, JniHandleOwnership transfer, System.Type type) [0x00000] in <filename unknown>:0
E/mono    ( 2906):   at Java.Lang.Object._GetObject[IJavaObject] (IntPtr handle, JniHandleOwnership transfer) [0x00000

如果包含子类 (IntPtr,JniHandleOwnership) 构造函数,则将创建类型的实例。If the subclass does contain an (IntPtr, JniHandleOwnership) constructor, then a new instance of the type will be created. 因此,实例将显示"丢失"所有实例数据,因为它是一个新实例。As a result, the instance will appear to "lose" all instance data, as it's a new instance. (请注意的值为 null)。(Note that the Value is null.)

I/mono-stdout( 2993): [Managed: Value=]

dispose () 的当您知道将不再,使用 Java 对象或子类不包含任何实例数据和托管可调用包装器子类 (IntPtr,JniHandleOwnership) 提供了构造函数。Only Dispose() of managed callable wrapper subclasses when you know that the Java object will not be used anymore, or the subclass contains no instance data and a (IntPtr, JniHandleOwnership) constructor has been provided.

应用程序启动Application Startup

当一种活动、 服务时,等启动时,Android 将首先检查以查看是否已运行托管活动/service/等的进程。如果不存在任何此类进程,则将创建一个新进程, AndroidManifest.xml是读取,和中指定的类型 /manifest/application/@android:name 加载和实例化属性。When an activity, service, etc. is launched, Android will first check to see if there is already a process running to host the activity/service/etc. If no such process exists, then a new process will be created, the AndroidManifest.xml is read, and the type specified in the /manifest/application/@android:name attribute is loaded and instantiated. 接下来,通过指定的所有类型 /manifest/application/provider/@android:name 属性值进行实例化,并且具有其ContentProvider.attachInfo%28)调用方法。Next, all types specified by the /manifest/application/provider/@android:name attribute values are instantiated and have their ContentProvider.attachInfo%28) method invoked. 通过添加到此 Xamarin.Android 挂钩mono。MonoRuntimeProvider ContentProvider到在生成过程中的 AndroidManifest.xml。Xamarin.Android hooks into this by adding a mono.MonoRuntimeProvider ContentProvider to AndroidManifest.xml during the build process. Mono。MonoRuntimeProvider.attachInfo() 方法负责加载到进程中的 Mono 运行时。The mono.MonoRuntimeProvider.attachInfo() method is responsible for loading the Mono runtime into the process. 在此点之前使用 Mono 的任何尝试将失败。Any attempts to use Mono prior to this point will fail. (注意:这就是为什么类型的子类Android.App.Application需要提供(IntPtr,JniHandleOwnership) 构造函数,可以初始化 Mono 之前创建的应用程序实例。)( Note: This is why types which subclass Android.App.Application need to provide an (IntPtr, JniHandleOwnership) constructor, as the Application instance is created before Mono can be initialized.)

完成过程初始化后,AndroidManifest.xml参考查找以启动活动/service/等的类名称。Once process initialization has completed, AndroidManifest.xml is consulted to find the class name of the activity/service/etc. to launch. 例如, /manifest/application/activity/@android:name属性用于确定要加载的活动的名称。For example, the /manifest/application/activity/@android:name attribute is used to determine the name of an Activity to load. 为活动,此类型必须继承android.app.ActivityFor Activities, this type must inherit android.app.Activity. 通过加载指定的类型Class.forName() (这需要的类型为 Java 类型,因此 Android 可调用包装器),然后实例化。The specified type is loaded via Class.forName() (which requires that the type be a Java type, hence the Android Callable Wrappers), then instantiated. Android 可调用包装器实例的创建将触发相应的 C# 类型的实例的创建。Creation of an Android Callable Wrapper instance will trigger creation of an instance of the corresponding C# type. Android 将随后调用Activity.onCreate(Bundle) ,这将导致相应Activity.OnCreate(Bundle)被调用,就可以关闭到的资源争用。Android will then invoke Activity.onCreate(Bundle) , which will cause the corresponding Activity.OnCreate(Bundle) to be invoked, and you're off to the races.