The dot42 compiler compiles your C# code to an Android package (APK). This APK contains dex only. The dot42 compiler attempts to include only code that is actually needed in order to minimize the size of the APK. This is obviously desired for mobile devices (a design strategy you will find throughout Android).
This article explains how dot42 decides what code to exclude from the package.
Less obvious are method overrides. If a virtual method Foo() is reachable, then all overriden Foo() methods of derived classes will be marked reachable. A similar rule applies to explicit method overrides used in explicit interface implementations.
A special case is a virtual methods that overrides a method in the Android framework. Even if this method is not being called from your code, it must still be marked reachable if the declaring type is marked reachable. For example if your derive from Activity and provide your own OnCreate method, you want your own OnCreate to be used and not the base implementation. So we should include it.
Other special cases include default constructors (because they are required by the Dalvik VM), class constructors (also known as static contructors) and explicitly marked methods (see next).
Key to the reachable detection phase is identifying the roots of the application. These are all public types of your assembly.
The most important attribute is the Dot42.IncludeAttribute. By attaching it to a type or member, that type or member will be considered a root of the application. Example:
If you are using the onClick attribute of a button in a layout file like this:
See the dot42 API reference for more dot42 attributes that deal with event handlers and custom views.
This article explains how dot42 decides what code to exclude from the package.
Reachable detection phase
Before the dot42 compiler converts IL (or .NET code) to dex, it goes through a reachable detection phase. During this phase it marks types and members reachable if they can somehow be reached from one of the roots of the application. For example a method that is called from one of the roots is marked reachable. The same is true for methods that are called from methods that have already been marked reachable. This is an iterative process that ends after no new reachable code is found.Less obvious are method overrides. If a virtual method Foo() is reachable, then all overriden Foo() methods of derived classes will be marked reachable. A similar rule applies to explicit method overrides used in explicit interface implementations.
A special case is a virtual methods that overrides a method in the Android framework. Even if this method is not being called from your code, it must still be marked reachable if the declaring type is marked reachable. For example if your derive from Activity and provide your own OnCreate method, you want your own OnCreate to be used and not the base implementation. So we should include it.
Other special cases include default constructors (because they are required by the Dalvik VM), class constructors (also known as static contructors) and explicitly marked methods (see next).
Key to the reachable detection phase is identifying the roots of the application. These are all public types of your assembly.
Explicitly marked types and members
There are situations in which a type or member is not reachable from your code per the rules above, but you still want to include it. Examples are a custom view that is referenced in your layout resource, use of reflection or because of (unit) testing. For such cases, dot42 has defined custom attributes that can be attached to a type or member.The most important attribute is the Dot42.IncludeAttribute. By attaching it to a type or member, that type or member will be considered a root of the application. Example:
[Include] void Foo() {}This can also be done conditionally:
[Include(TypeCondition = typeof(SomeOtherType)] void Foo2() {}Foo2 method will only be marked reachable if SomeOtherType is reachable.
If you are using the onClick attribute of a button in a layout file like this:
<button android:layout_height="wrap_content" android:layout_width="wrap_content" android:onClick="OnButtonClick" android:text="@string/Sum" />Then you should use the EventHandler attribute to ensure the event handler is included:
[EventHandler] public void OnButtonClick(View view) {}By using EventHandler instead of Include, you protect it from being renamed.
See the dot42 API reference for more dot42 attributes that deal with event handlers and custom views.
Unit test types and methods
A final category that the dot42 compiler handles automatically are unit test types and methods. If you derive from TestCase, all methods named "test*" are automatically marked reachable. The same is true for methods that have an Nunit.Framework.Test or SetUp attribute attached to it. For example:/* included because its name starts with "test" */ public void testThisMethodIsIncluded() {}
/* included because of the Test attribute */ [Test] public void ThisMethodIsAlsoInclude() {}
No comments:
Post a Comment