共用方式為


疑難排解秘訣

取得診斷資訊

追蹤各種 Bug 時,Xamarin.Android 有幾個地方可查看。 包括:

  1. 診斷 MSBuild 輸出。
  2. 裝置部署記錄。
  3. Android 偵錯記錄輸出。

診斷 MSBuild 輸出

診斷 MSBuild 可以包含與套件建置相關的其他資訊,而且可能包含一些套件部署資訊。

若要在 Visual Studio 內啟用診斷 MSBuild 輸出:

  1. 點選 「 工具 > 選項...
  2. 在左側樹檢視中,選取 [專案和方案 > 建置並執行]
  3. 在右側面板中,將 MSBuild 建置輸出詳細資訊下拉式清單設定為 [診斷]
  4. 按一下 [檔案] > [新增] > [專案]
  5. 清除並重建您的套件。
  6. 診斷輸出會顯示在 [輸出] 面板中。

若要在 Visual Studio for Mac/OS X 內啟用診斷 MSBuild 輸出:

  1. 按兩下 [Visual Studio for Mac > 喜好設定...
  2. 在左側樹檢視中,選取 [專案建置]>
  3. 在右側面板中,將 [記錄詳細資訊] 下拉式清單設定為 [診斷]
  4. 按一下 [檔案] > [新增] > [專案]
  5. 重新啟動 Visual Studio for Mac
  6. 清除並重建您的套件。
  7. 按兩下 [建置輸出] 按鈕,即可在 Errors Pad (View > Pads > Errors ) 內看見診斷輸出。

裝置部署記錄

若要在 Visual Studio 中啟用裝置部署記錄:

  1. 工具 > 選項...>
  2. 在左側樹檢視中,選取 [Xamarin > Android 設定
  3. 在右側面板中,啟用 [X] 延伸模組偵錯記錄 (將monodroid.log寫入桌面) 複選框。
  4. 記錄訊息會寫入桌面上的monodroid.log檔案。

Visual Studio for Mac 一律會寫入裝置部署記錄。 FInding 它們稍微困難一點: AndroidUtils 記錄檔會針對發生部署的每一天 + 時間建立,例如: AndroidTools-2012-10-24_12-35-45.log

  • 在 Windows 上,記錄檔會 %LOCALAPPDATA%\XamarinStudio-{VERSION}\Logs寫入 。
  • 在 OS X 上,記錄檔會寫入 $HOME/Library/Logs/XamarinStudio-{VERSION}

Android 偵錯記錄輸出

Android 會將許多訊息 寫入 Android 偵錯記錄檔。 Xamarin.Android 使用 Android 系統屬性來控制對 Android 偵錯記錄檔的額外訊息產生。 Android 系統屬性可以透過 Android 偵錯網橋 (adb) 內的 setprop 命令來設定:

adb shell setprop PROPERTY_NAME PROPERTY_VALUE

系統屬性會在進程啟動期間讀取,因此必須在啟動應用程式之前設定,或者必須在系統屬性變更之後重新啟動應用程式。

Xamarin.Android 系統屬性

Xamarin.Android 支援下列系統屬性:

  • debug.mono.debug:如果非空字串,這相當於 *mono-debug*

  • debug.mono.env:在初始化mono之前,在應用程式啟動期間要導出的管線分隔環境變數|清單。 這允許設定控制Mono記錄的環境變數。

    注意

    由於值為 『|-separated,因此值必須有額外的引號層級,因為 『adb shell』 命令會移除一組引號。

    注意

    Android 系統屬性值長度不能超過92個字元。

    範例:

    adb shell setprop debug.mono.env "'MONO_LOG_LEVEL=info|MONO_LOG_MASK=asm'"
    
  • debug.mono.log:應該將其他訊息列印至 Android 偵錯記錄檔的逗號分隔元件清單。 根據預設,不會設定任何專案。 元件包括:

    • all:列印所有訊息
    • gc:列印 GC 相關訊息。
    • gref:列印(弱式、全域)參考配置和解除分配訊息。
    • lref:印表本機參考配置和解除分配訊息。

    注意

    這些非常詳細。 除非您真的需要啟用,否則請勿啟用。

  • debug.mono.trace:允許設定 mono --trace=PROPERTY_VALUE 設定。

刪除 binobj

Xamarin.Android 過去曾遭受過下列情況:

  • 您遇到奇怪的組建或運行時間錯誤。
  • CleanRebuild或手動移除和 binobj 目錄。
  • 問題消失了。

由於這些問題對開發人員生產力的影響,我們投入了大量資金來修正這類問題。

如果您遇到這類問題:

  1. 記下精神筆記。 您的項目進入此狀態的最後一個動作為何?
  2. 儲存目前的組建記錄檔。 再次嘗試建置,並記錄 診斷建置記錄
  3. 提交 Bug 報告

刪除您的 binobj 目錄之前,請將其壓縮並加以儲存,以供稍後視需要進行診斷。 您可能只是 Clean 您的 Xamarin.Android 應用程式專案,才能讓專案再次運作。

Xamarin.Android 無法解析 System.ValueTuple

此錯誤是因為 Visual Studio 不相容而發生。

  • Visual Studio 2017 Update 1 (15.1 版或更新版本)僅與 System.ValueTuple NuGet 4.3.0 (或較舊版本)相容。

  • Visual Studio 2017 Update 2 (15.2 版或更新版本)僅與 System.ValueTuple NuGet 4.3.1 (或更新版本)相容。

請選擇與Visual Studio 2017 安裝對應的正確 System.ValueTuple NuGet。

GC 訊息

您可以將 debug.mono.log 系統屬性設定為包含 gc 的值,即可檢視 GC 元件訊息。

每當 GC 執行時,就會產生 GC 訊息,並提供 GC 執行多少工作的相關信息:

I/monodroid-gc(12331): GC cleanup summary: 81 objects tested - resurrecting 21.

將環境變數debug設定MONO_LOG_LEVEL為 ,即可產生其他 GC 資訊,例如計時資訊:

adb shell setprop debug.mono.env MONO_LOG_LEVEL=debug

這會導致額外的Mono訊息,包括下列三個結果:

D/Mono (15723): GC_BRIDGE num-objects 1 num_hash_entries 81226 sccs size 81223 init 0.00ms df1 285.36ms sort 38.56ms dfs2 50.04ms setup-cb 9.95ms free-data 106.54ms user-cb 20.12ms clenanup 0.05ms links 5523436/5523436/5523096/1 dfs passes 1104 6883/11046605
D/Mono (15723): GC_MINOR: (Nursery full) pause 2.01ms, total 287.45ms, bridge 225.60 promoted 0K major 325184K los 1816K
D/Mono ( 2073): GC_MAJOR: (user request) pause 2.17ms, total 2.47ms, bridge 28.77 major 576K/576K los 0K/16K

在訊息中 GC_BRIDGEnum-objects 這是這個階段所考慮的網橋物件數目,而且 num_hash_entries 是在網橋程式代碼調用期間處理的物件數目。

GC_MINORGC_MAJOR 訊息中, total 是暫停世界的時間量(沒有線程正在執行),而 bridge 是橋接處理程式代碼中花費的時間量(處理 Java VM)。 橋接處理發生時,世界 不會 暫停。

一般而言,值 num_hash_entries愈大,集合所花費的時間 bridge 愈多,所花費的時間就越大 total

全域參考訊息

若要啟用全域參考記錄 (GREF) 記錄, debug.mono.log 系統屬性必須包含 gref,例如:

adb shell setprop debug.mono.log gref

Xamarin.Android 會使用 Android 全域參考來提供 Java 實例與相關聯受控實例之間的對應,就像叫用 Java 方法時,需要將 Java 實例提供給 Java 時一樣。

不幸的是,Android 模擬器一次只允許有 2000 個全域參考存在。 硬體有 52000 個全域參考的更高限制。 在模擬器上執行應用程式時,下限可能會有問題,因此知道實例的來源可能非常實用。

注意

全域參考計數是 Xamarin.Android 的內部,且不包含載入進程的其他原生連結庫所取出的全域參考。。 使用全域參考計數作為估計值。

I/monodroid-gref(12405): +g+ grefc 108 gwrefc 0 obj-handle 0x40517468/L -> new-handle 0x40517468/L from    at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405):    at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405):    at Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer)
I/monodroid-gref(12405):    at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable)
I/monodroid-gref(12405):    at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler)
I/monodroid-gref(12405):    at Android.App.Activity.RunOnUiThread(System.Action action)
I/monodroid-gref(12405):    at Mono.Samples.Hello.HelloActivity.UseLotsOfMemory(Android.Widget.TextView textview)
I/monodroid-gref(12405):    at Mono.Samples.Hello.HelloActivity.<OnCreate>m__3(System.Object o)
I/monodroid-gref(12405): handle 0x40517468; key_handle 0x40517468: Java Type: `mono/java/lang/RunnableImplementor`; MCW type: `Java.Lang.Thread+RunnableImplementor`
I/monodroid-gref(12405): Disposing handle 0x40517468
I/monodroid-gref(12405): -g- grefc 107 gwrefc 0 handle 0x40517468/L from    at Java.Lang.Object.Dispose(System.Object instance, IntPtr handle, IntPtr key_handle, JObjectRefType handle_type)
I/monodroid-gref(12405):    at Java.Lang.Object.Dispose()
I/monodroid-gref(12405):    at Java.Lang.Thread+RunnableImplementor.Run()
I/monodroid-gref(12405):    at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)
I/monodroid-gref(12405):    at System.Object.c200fe6f-ac33-441b-a3a0-47659e3f6750(IntPtr , IntPtr )
I/monodroid-gref(27679): +w+ grefc 1916 gwrefc 296 obj-handle 0x406b2b98/G -> new-handle 0xde68f4bf/W from take_weak_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1915 gwrefc 294 handle 0xde691aaf/W from take_global_ref_jni

結果有四則訊息:

  • 全域參考建立:這些是以 +g+ 開頭的幾行,並提供建立程式代碼路徑的堆棧追蹤。
  • 全域參考解構:這些是開頭 為 -g- 的行,而且可能會為處置全域參考的程式代碼路徑提供堆棧追蹤。 如果 GC 正在處置 gref,則不會提供任何堆疊追蹤。
  • 弱式全域參考建立:這些是以 +w+ 開頭的行。
  • 弱式全域參考解構:這些是以 -w- 開頭的 行。

在所有訊息中, grefc 值是 Xamarin.Android 建立的全域參考計數,而 grefwc 值則是 Xamarin.Android 所建立的弱式全域參考計數。 句柄obj-handle 值是 JNI 句柄值,而 ' /' 後面的字元是句柄值的類型:/L 代表本機參考、/G 代表全域參考,以及弱式全域參考的 /W

作為 GC 程式的一部分,全域參考 (+g+) 會轉換成弱式全域參考(導致 +w+ 和 -g-),會踢出 Java 端 GC,然後檢查弱式全域參考,以查看是否已收集。 如果仍然運作,則會在弱式 ref (+g+, -w-) 周圍建立新的 gref,否則弱式 ref 會終結 (-w)。

Java 實例是由MCW建立和包裝

I/monodroid-gref(27679): +g+ grefc 2211 gwrefc 0 obj-handle 0x4066df10/L -> new-handle 0x4066df10/L from ...
I/monodroid-gref(27679): handle 0x4066df10; key_handle 0x4066df10: Java Type: `android/graphics/drawable/TransitionDrawable`; MCW type: `Android.Graphics.Drawables.TransitionDrawable`

執行 GC...

I/monodroid-gref(27679): +w+ grefc 1953 gwrefc 259 obj-handle 0x4066df10/G -> new-handle 0xde68f95f/W from take_weak_global_ref_jni
I/monodroid-gref(27679): -g- grefc 1952 gwrefc 259 handle 0x4066df10/G from take_weak_global_ref_jni

物件仍在運作中,因為句柄 != null

wref 已重新變成 gref

I/monodroid-gref(27679): *try_take_global obj=0x4976f080 -> wref=0xde68f95f handle=0x4066df10
I/monodroid-gref(27679): +g+ grefc 1930 gwrefc 39 obj-handle 0xde68f95f/W -> new-handle 0x4066df10/G from take_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1930 gwrefc 38 handle 0xde68f95f/W from take_global_ref_jni

物件已失效,因為 handle == null

wref 已釋出,未建立新的 gref

I/monodroid-gref(27679): *try_take_global obj=0x4976f080 -> wref=0xde68f95f handle=0x0
I/monodroid-gref(27679): -w- grefc 1914 gwrefc 296 handle 0xde68f95f/W from take_global_ref_jni

這裡有一個「有趣的」皺紋:在 4.0 之前執行 Android 的目標上,gref 值等於 Android 運行時間記憶體中 Java 物件的位址。 (也就是說,GC 是一個不移動、保守、收集器,而且它正在直接參考這些物件。因此,在 +g+、+、-g-、+g+、-w- 序列之後,產生的 gref 值會與原始 gref 值相同。 這讓記錄變得相當簡單。

不過,Android 4.0 具有移動收集器,不再直接參考 Android 運行時間 VM 物件。 因此,在 +g+、+w+、-g-、-g+、-w- 序列之後,gref 值 會不同。 如果物件在多個DC中倖存下來,它會由數個 gref 值執行,因此很難判斷實例實際配置的來源。

以程式設計方式查詢

您可以查詢 物件來查詢 GREF 和 WREF 計數 JniRuntime

Java.Interop.JniRuntime.CurrentRuntime.GlobalReferenceCount - 全域參考計數

Java.Interop.JniRuntime.CurrentRuntime.WeakGlobalReferenceCount - 弱式參考計數

Android 偵錯記錄

Android 偵 錯記錄 可能會提供有關您所看到之任何運行時錯誤的其他內容。

浮點效能太可怕了!

或者,「我的應用程式使用偵錯組建執行速度比發行組建快 10 倍!

Xamarin.Android 支援多個裝置 ABIS:armeabi、armeabi-v7ax86。 您可以在 [項目屬性>應用程式] 索引標籤>指定裝置 ABIS 支援架構

偵錯組建會使用提供所有 ABI 的 Android 套件,因此會針對目標裝置使用最快的 ABI。

發行組建只會包含 [項目屬性] 索引標籤中選取的 ABIS。可以選擇多個 。

armeabi 是預設的 ABI,且具有最廣泛的裝置支援。 不過,armeabi 不支援多 CPU 裝置和硬體浮點數,還有其他專案。 因此,使用armeabi Release運行時間的應用程式將會繫結至單一核心,並使用軟浮點實作。 這兩者都有助於大幅降低應用程式的效能。

如果您的 app 需要體面的浮點效能(例如遊戲),您應該啟用 armeabi-v7a ABI。 您可能只想要支援 armeabi-v7a 運行時間,但這表示僅支援 armeabi 的較舊裝置將無法執行您的應用程式。

找不到 Android SDK

Android SDK for Windows 有 2 個可供 Google 下載。 如果您選擇.exe安裝程式,它會寫入登錄機碼,告知 Xamarin.Android 安裝的位置。 如果您選擇.zip檔案並自行解壓縮,Xamarin.Android 並不知道要在哪裡尋找 SDK。 您可以移至 [工具>選項 > Xamarin Android] 設定告訴 Xamarin.Android > SDK 在 Visual Studio 中的位置:

Android SDK Location in Xamarin Android Settings

IDE 不會顯示目標裝置

有時候您會嘗試將應用程式部署至裝置,但您想要部署的裝置不會顯示在 [選取裝置] 對話框中。 當Android偵錯網橋決定休假時,就會發生這種情況。

若要診斷此問題,請尋找 adb 程式,然後執行:

adb devices

如果您的裝置不存在,您必須重新啟動 Android Debug Bridge 伺服器,才能找到您的裝置:

adb kill-server
adb start-server

TC 同步處理軟體可能會防止 adb 啟動伺服器 正常運作。 如果 adb start-server 命令未列印要啟動的埠,請結束HTC 同步處理軟體,並嘗試重新啟動 adb 伺服器。

無法執行指定的工作可執行檔 “keytool”

這表示您的PATH不包含Java SDK bin 目錄所在的目錄。 請檢查您遵循安裝指南中的這些步驟。

monodroid.exe或aresgen.exe以代碼 1 結束

若要協助您偵錯此問題,請移至 Visual Studio 並變更 MSBuild 詳細資訊層級,若要這樣做,請選取:工具選項專案和方案>建置和執行 >MSBuild 專案建置輸出詳細資訊,並將此值設定為 [一般]。>>

重建並檢查 Visual Studio 的 [輸出] 窗格,其中應該包含完整的錯誤。

裝置上沒有足夠的儲存空間來部署套件

當您未從 Visual Studio 內啟動模擬器時,就會發生這種情況。 在 Visual Studio 外部啟動模擬器時,您需要傳遞 -partition-size 512 選項,例如

emulator -partition-size 512 -avd MonoDroid

請確定您使用正確的模擬器名稱,也就是 您在設定模擬器時所使用的名稱。

安裝套件時INSTALL_FAILED_INVALID_APK

Android 套件名稱必須包含句號 ('.')。 編輯您的套件名稱,使其包含句點。

  • 在 Visual Studio 内:
    • 以滑鼠右鍵按下您的專案 > [屬性]
    • 按兩下左側的 [Android 指令清單] 索引標籤。
    • 更新 [套件名稱] 欄位。
      • 如果您看到訊息「找不到AndroidManifest.xml。 按兩下以新增一個。“,按兩下連結,然後更新 [套件名稱] 字段。
  • 在 Visual Studio for Mac 內:
    • 以滑鼠右鍵按下您的專案 > [選項]。
    • 流覽至 [建置/ Android 應用程式] 區段。
    • 將 [套件名稱] 字段變更為包含 '.'。

安裝套件時INSTALL_FAILED_MISSING_SHARED_LIBRARY

此內容中的「共享連結庫」不是原生共享連結庫 (libfoo.so) 檔案;而是必須在目標裝置上個別安裝的連結庫,例如 Google 地圖。

Android 套件會指定元素需要 <uses-library/> 哪些共享連結庫。 如果目標裝置上沒有必要的連結庫(例如 //uses-library/@android:required true,也就是預設值),則套件安裝將會失敗並INSTALL_FAILED_MISSING_SHARED_LIBRARY

若要判斷需要哪些共享連結庫,請檢視產生的AndroidManifest.xml檔案(例如 obj\Debug\android\AndroidManifest.xml),並尋找<uses-library/>元素。 <uses-library/>您可以透過 UsesLibraryAttribute 自定義屬性,在專案的 Properties\AndroidManifest.xml 檔案中手動新增元素。

例如,將元件參考新增至Mono.Android.Google 地圖.dll會隱含新增 <uses-library/> Google 地圖共用文件庫的 。

安裝套件時INSTALL_FAILED_UPDATE_INCOMPATIBLE

Android 套件有三個需求:

  • 它們必須包含 '.'(請參閱上一個專案)
  • 它們必須有唯一的字串套件名稱(因此Android 應用程式名稱中看到的反向tld 慣例,e.g. com.android.chrome for the Chrome app)
  • 升級套件時,套件必須具有相同的簽署密鑰。

因此,假設此案例:

  1. 您建置應用程式並將其部署為偵錯應用程式
  2. 您可以變更簽署金鑰,例如將 作為發行應用程式使用(或因為您不喜歡預設提供的偵錯簽署金鑰)
  3. 您不需要先將其移除即可安裝應用程式,例如 > 在 Visual Studio 中偵錯啟動但不偵錯

發生這種情況時,套件安裝將會失敗,併發生INSTALL_FAILED_UPDATE_INCOMPATIBLE錯誤,因為簽署密鑰時套件名稱未變更。 Android 偵 錯記錄 檔也會包含類似下列訊息:

E/PackageManager(  146): Package [PackageName] signatures do not match the previously installed version; ignoring!

若要修正此錯誤,請在重新安裝之前,先從裝置完全移除應用程式。

安裝套件時INSTALL_FAILED_UID_CHANGED

安裝 Android 套件時,會指派 使用者識別碼 (UID)。 有時候,基於目前未知的原因,在透過已安裝的應用程式進行安裝時,安裝將會失敗:INSTALL_FAILED_UID_CHANGED

ERROR [2015-03-23 11:19:01Z]: ANDROID: Deployment failed
Mono.AndroidTools.InstallFailedException: Failure [INSTALL_FAILED_UID_CHANGED]
   at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName)
   at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass2c.<InstallPackage>b__2b(Task`1 t)
   at System.Threading.Tasks.ContinuationTaskFromResultTask`1.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()

若要解決此問題, 請完全卸載 Android 套件,方法是從 Android 目標 GUI 安裝應用程式,或使用 adb

$ adb uninstall @PACKAGE_NAME@

請勿使用adb uninstall -k,因為這樣會 保留 應用程式數據,因此會保留目標裝置上衝突的 UID。

發行應用程式無法在裝置上啟動

Android 偵錯記錄輸出是否包含類似下列的訊息:

D/AndroidRuntime( 1710): Shutting down VM
W/dalvikvm( 1710): threadid=1: thread exiting with uncaught exception (group=0xb412f180)
E/AndroidRuntime( 1710): FATAL EXCEPTION: main
E/AndroidRuntime( 1710): java.lang.UnsatisfiedLinkError: Couldn't load monodroid: findLibrary returned null
E/AndroidRuntime( 1710):        at java.lang.Runtime.loadLibrary(Runtime.java:365)

若是如此,則有兩個可能的原因:

  1. .apk不提供目標裝置支援的 ABI。 例如,.apk只包含armeabi-v7a二進位檔,而目標裝置僅支援armeabi。

  2. Android Bug。 如果是這種情況,請卸載應用程式、交叉手指,然後重新安裝應用程式。

若要修正 (1),請編輯專案選項/屬性,並將 所需 ABI 的支援新增至支援的 ABI 清單。 若要判斷您需要新增的 ABI,請對目標裝置執行下列 adb 命令:

adb shell getprop ro.product.cpu.abi
adb shell getprop ro.product.cpu.abi2

輸出將包含主要 (和選擇性的次要) API。

$ adb shell getprop | grep ro.product.cpu
[ro.product.cpu.abi2]: [armeabi]
[ro.product.cpu.abi]: [armeabi-v7a]

未針對專案 「MyApp.csproj」 設定 OutPath 屬性

這通常表示您有 HP 計算機,且環境變數 「Platform」 已設定為 MCD 或 HPD 之類的專案。 這與一般設定為 「Any CPU」 或 「x86」 的 MSBuild Platform 屬性衝突。 您必須先從機器移除此環境變數,MSBuild 才能運作:

  • > 控制台 系統>進階>環境變數

重新啟動 Visual Studio 或 Visual Studio for Mac,並嘗試重建。 事情現在應該如預期般運作。

java.lang.ClassCastException:mono.android.runtime.JavaObject 無法轉換成...

Xamarin.Android 4.x 無法正確封送處理巢狀泛型類型。 例如,請考慮使用 SimpleExpandableListAdapter 的下列 C# 程式代碼:

// BAD CODE; DO NOT USE
var groupData = new List<IDictionary<string, object>> () {
        new Dictionary<string, object> {
                { "NAME", "Group 1" },
                { "IS_EVEN", "This group is odd" },
        },
};
var childData = new List<IList<IDictionary<string, object>>> () {
        new List<IDictionary<string, object>> {
                new Dictionary<string, object> {
                        { "NAME", "Child 1" },
                        { "IS_EVEN", "This group is odd" },
                },
        },
};
mAdapter = new SimpleExpandableListAdapter (
        this,
        groupData,
        Android.Resource.Layout.SimpleExpandableListItem1,
        new string[] { "NAME", "IS_EVEN" },
        new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 },
        childData,
        Android.Resource.Layout.SimpleExpandableListItem2,
        new string[] { "NAME", "IS_EVEN" },
        new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 }
);

問題是 Xamarin.Android 錯誤地封送處理巢狀泛型類型。 List<IDictionary<string, object>>正在封送處理至 java.lang.ArrrayList,但 ArrayList 包含mono.android.runtime.JavaObject實例(參考Dictionary<string, object>實例),而不是實作 java.util.Map 的內容,導致下列例外狀況:

E/AndroidRuntime( 2991): FATAL EXCEPTION: main
E/AndroidRuntime( 2991): java.lang.ClassCastException: mono.android.runtime.JavaObject cannot be cast to java.util.Map
E/AndroidRuntime( 2991):        at android.widget.SimpleExpandableListAdapter.getGroupView(SimpleExpandableListAdapter.java:278)
E/AndroidRuntime( 2991):        at android.widget.ExpandableListConnector.getView(ExpandableListConnector.java:446)
E/AndroidRuntime( 2991):        at android.widget.AbsListView.obtainView(AbsListView.java:2271)
E/AndroidRuntime( 2991):        at android.widget.ListView.makeAndAddView(ListView.java:1769)
E/AndroidRuntime( 2991):        at android.widget.ListView.fillDown(ListView.java:672)
E/AndroidRuntime( 2991):        at android.widget.ListView.fillFromTop(ListView.java:733)
E/AndroidRuntime( 2991):        at android.widget.ListView.layoutChildren(ListView.java:1622)

因應措施是使用提供的 Java 集合類型 ,而不是 System.Collections.Generic 「內部」型別的類型。 這會導致在封送處理實例時產生適當的Java類型。 (下列程序代碼比必要程序代碼複雜,以減少 gref 存留期。您可以簡化變更原始程序代碼, s/List/JavaList/g 如果 s/Dictionary/JavaDictionary/g gref 存留期不擔心的話。

// insert good code here
using (var groupData = new JavaList<IDictionary<string, object>> ()) {
    using (var groupEntry = new JavaDictionary<string, object> ()) {
        groupEntry.Add ("NAME", "Group 1");
        groupEntry.Add ("IS_EVEN", "This group is odd");
        groupData.Add (groupEntry);
    }
    using (var childData = new JavaList<IList<IDictionary<string, object>>> ()) {
        using (var childEntry = new JavaList<IDictionary<string, object>> ())
        using (var childEntryDict = new JavaDictionary<string, object> ()) {
            childEntryDict.Add ("NAME", "Child 1");
            childEntryDict.Add ("IS_EVEN", "This child is odd.");
            childEntry.Add (childEntryDict);
            childData.Add (childEntry);
        }
        mAdapter = new SimpleExpandableListAdapter (
            this,
            groupData,
            Android.Resource.Layout.SimpleExpandableListItem1,
            new string[] { "NAME", "IS_EVEN" },
            new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 },
            childData,
            Android.Resource.Layout.SimpleExpandableListItem2,
            new string[] { "NAME", "IS_EVEN" },
            new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 }
        );
    }
}

Unexpected NullReferenceExceptions

Android 偵錯記錄偶爾會提及「無法發生」的 NullReferenceExceptions,或來自 Android 運行時間程式代碼的 Mono,然後應用程式即會死亡:

E/mono(15202): Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object
E/mono(15202):   at Java.Lang.Object.GetObject (IntPtr handle, System.Type type, Boolean owned)
E/mono(15202):   at Java.Lang.Object._GetObject[IOnTouchListener] (IntPtr handle, Boolean owned)
E/mono(15202):   at Java.Lang.Object.GetObject[IOnTouchListener] (IntPtr handle, Boolean owned)
E/mono(15202):   at Android.Views.View+IOnTouchListenerAdapter.n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent_(IntPtr jnienv, IntPtr native__this, IntPtr native_v, IntPtr native_e)
E/mono(15202):   at (wrapper dynamic-method) object:b039cbb0-15e9-4f47-87ce-442060701362 (intptr,intptr,intptr,intptr)

E/mono    ( 4176): Unhandled Exception:
E/mono    ( 4176): System.NullReferenceException: Object reference not set to an instance of an object
E/mono    ( 4176): at Android.Runtime.JNIEnv.NewString (string)
E/mono    ( 4176): at Android.Util.Log.Info (string,string)

當 Android 執行時間決定中止程式時,可能會因為任何原因而發生,包括達到目標的 GREF 限制,或使用 JNI 執行「錯誤」動作。

若要查看此情況,請檢查 Android 偵錯記錄中是否有類似下列程式的訊息:

E/dalvikvm(  123): VM aborting

因全域參考耗盡而中止

Android 運行時間的 JNI 層僅支援有限數目的 JNI 物件參考,在任何指定的時間點都有效。 超過此限制時,情況會中斷。

GREF (全域參考) 限制是模擬器中的 2000 個參考,而硬體上的 ~52000 參考。

您知道當您在 Android 偵錯記錄中看到這類訊息時,會開始建立太多 GREF:

D/dalvikvm(  602): GREF has increased to 1801

當您達到 GREF 限制時,會列印如下的訊息:

D/dalvikvm(  602): GREF has increased to 2001
W/dalvikvm(  602): Last 10 entries in JNI global reference table:
W/dalvikvm(  602):  1991: 0x4057eff8 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1992: 0x4057f010 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(  602):  1993: 0x40698e70 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1994: 0x40698e88 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1995: 0x40698ea0 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(  602):  1996: 0x406981f0 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1997: 0x40698208 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  1998: 0x40698220 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(  602):  1999: 0x406956a8 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602):  2000: 0x406956c0 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(  602): JNI global reference table summary (2001 entries):
W/dalvikvm(  602):    51 of Ljava/lang/Class; 164B (41 unique)
W/dalvikvm(  602):    46 of Ljava/lang/Class; 188B (17 unique)
W/dalvikvm(  602):     6 of Ljava/lang/Class; 212B (6 unique)
W/dalvikvm(  602):    11 of Ljava/lang/Class; 236B (7 unique)
W/dalvikvm(  602):     3 of Ljava/lang/Class; 260B (3 unique)
W/dalvikvm(  602):     4 of Ljava/lang/Class; 284B (2 unique)
W/dalvikvm(  602):     8 of Ljava/lang/Class; 308B (6 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 316B
W/dalvikvm(  602):     4 of Ljava/lang/Class; 332B (3 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 356B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 380B (1 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 428B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 452B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 476B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 500B (1 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 548B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 572B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 596B (2 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 692B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 956B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 1004B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 1148B
W/dalvikvm(  602):     2 of Ljava/lang/Class; 1172B (1 unique)
W/dalvikvm(  602):     1 of Ljava/lang/Class; 1316B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 3428B
W/dalvikvm(  602):     1 of Ljava/lang/Class; 3452B
W/dalvikvm(  602):     1 of Ljava/lang/String; 28B
W/dalvikvm(  602):     2 of Ldalvik/system/VMRuntime; 12B (1 unique)
W/dalvikvm(  602):    10 of Ljava/lang/ref/WeakReference; 28B (10 unique)
W/dalvikvm(  602):     1 of Ldalvik/system/PathClassLoader; 44B
W/dalvikvm(  602):  1553 of Landroid/graphics/Point; 20B (1553 unique)
W/dalvikvm(  602):   261 of Landroid/graphics/Point; 28B (261 unique)
W/dalvikvm(  602):     1 of Landroid/view/MotionEvent; 100B
W/dalvikvm(  602):     1 of Landroid/app/ActivityThread$ApplicationThread; 28B
W/dalvikvm(  602):     1 of Landroid/content/ContentProvider$Transport; 28B
W/dalvikvm(  602):     1 of Landroid/view/Surface$CompatibleCanvas; 44B
W/dalvikvm(  602):     1 of Landroid/view/inputmethod/InputMethodManager$ControlledInputConnectionWrapper; 36B
W/dalvikvm(  602):     1 of Landroid/view/ViewRoot$1; 12B
W/dalvikvm(  602):     1 of Landroid/view/ViewRoot$W; 28B
W/dalvikvm(  602):     1 of Landroid/view/inputmethod/InputMethodManager$1; 28B
W/dalvikvm(  602):     1 of Landroid/view/accessibility/AccessibilityManager$1; 28B
W/dalvikvm(  602):     1 of Landroid/widget/LinearLayout$LayoutParams; 44B
W/dalvikvm(  602):     1 of Landroid/widget/LinearLayout; 332B
W/dalvikvm(  602):     2 of Lorg/apache/harmony/xnet/provider/jsse/TrustManagerImpl; 28B (1 unique)
W/dalvikvm(  602):     1 of Landroid/view/SurfaceView$MyWindow; 36B
W/dalvikvm(  602):     1 of Ltouchtest/RenderThread; 92B
W/dalvikvm(  602):     1 of Landroid/view/SurfaceView$3; 12B
W/dalvikvm(  602):     1 of Ltouchtest/DrawingView; 412B
W/dalvikvm(  602):     1 of Ltouchtest/Activity1; 180B
W/dalvikvm(  602): Memory held directly by tracked refs is 75624 bytes
E/dalvikvm(  602): Excessive JNI global references (2001)
E/dalvikvm(  602): VM aborting

在上述範例中(順便說一句,來自 bug 685215),問題在於正在建立太多 Android.Graphics.Point 實例;如需此特定 Bug 的修正清單,請參閱 批注 #2

一般而言,有用的解決方案是尋找在上述傾印中配置了太多實例的 Android.Graphics.Point ,然後找出在原始程式碼中建立的實例並適當處置它們的位置(以便縮短其 Java 物件存留期)。 這不一定是適當的(#685215是多线程的,所以微不足道的解決方案會避免 Dispose 呼叫),但這是第一個考慮事項。

您可以啟用 GREF 記錄 來查看建立 GREF 的時間,以及有多少存在。

因 JNI 類型不符而中止

如果您手動擲回 JNI 程式代碼,則類型可能不相符,例如,如果您嘗試在未實java.lang.Runnable作 的型別上叫java.lang.Runnable.run用 。 發生此情況時,Android 偵錯記錄檔中會有類似這樣的訊息:

W/dalvikvm( 123): JNI WARNING: can't call Ljava/Type;;.method on instance of Lanother/java/Type;
W/dalvikvm( 123):              in Lmono/java/lang/RunnableImplementor;.n_run:()V (CallVoidMethodA)
...
E/dalvikvm( 123): VM aborting

動態程式代碼支援

動態程式代碼未編譯

若要在應用程式或連結庫中使用 C# 動態,您必須將System.Core.dll、Microsoft.CSharp.dll和Mono.CSharp.dll新增至專案。

在發行組建中,MissingMethodException 會在運行時間針對動態程式代碼發生。

  • 您的應用程式專案可能沒有System.Core.dll、Microsoft.CSharp.dll或Mono.CSharp.dll的參考。 請確定參考這些元件。

    • 請記住,動態程式代碼一律會花費成本。 如果您需要有效率的程式代碼,請考慮不使用動態程序代碼。
  • 在第一個預覽版中,除非應用程式程式代碼明確使用每個元件中的類型,否則會排除這些元件。 如需因應措施,請參閱下列各項: http://lists.ximian.com/pipermail/mo...il/009798.html

以 AOT+LLVM 在 x86 裝置上建置的項目當機

在 x86 型裝置上部署以 AOT+LLVM 建置的應用程式時,您可能會看到類似下列的例外狀況錯誤訊息:

Assertion: should not be reached at /Users/.../external/mono/mono/mini/tramp-x86.c:124
Fatal signal 6 (SIGABRT), code -6 in tid 4051 (Xamarin.bug56111)

這是已知問題 – 因應措施是停用 LLVM。