疑難排解秘訣
取得診斷資訊
追蹤各種 Bug 時,Xamarin.Android 有幾個地方可查看。 包括:
- 診斷 MSBuild 輸出。
- 裝置部署記錄。
- Android 偵錯記錄輸出。
診斷 MSBuild 輸出
診斷 MSBuild 可以包含與套件建置相關的其他資訊,而且可能包含一些套件部署資訊。
若要在 Visual Studio 內啟用診斷 MSBuild 輸出:
- 點選 「 工具 > 選項...
- 在左側樹檢視中,選取 [專案和方案 > 建置並執行]
- 在右側面板中,將 MSBuild 建置輸出詳細資訊下拉式清單設定為 [診斷]
- 按一下 [檔案] > [新增] > [專案]
- 清除並重建您的套件。
- 診斷輸出會顯示在 [輸出] 面板中。
若要在 Visual Studio for Mac/OS X 內啟用診斷 MSBuild 輸出:
- 按兩下 [Visual Studio for Mac > 喜好設定...
- 在左側樹檢視中,選取 [專案建置]>
- 在右側面板中,將 [記錄詳細資訊] 下拉式清單設定為 [診斷]
- 按一下 [檔案] > [新增] > [專案]
- 重新啟動 Visual Studio for Mac
- 清除並重建您的套件。
- 按兩下 [建置輸出] 按鈕,即可在 Errors Pad (View > Pads > Errors ) 內看見診斷輸出。
裝置部署記錄
若要在 Visual Studio 中啟用裝置部署記錄:
- 工具 > 選項...>
- 在左側樹檢視中,選取 [Xamarin > Android 設定
- 在右側面板中,啟用 [X] 延伸模組偵錯記錄 (將monodroid.log寫入桌面) 複選框。
- 記錄訊息會寫入桌面上的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
設定。
刪除 bin
和 obj
Xamarin.Android 過去曾遭受過下列情況:
- 您遇到奇怪的組建或運行時間錯誤。
- 您
Clean
、Rebuild
或手動移除和bin
obj
目錄。 - 問題消失了。
由於這些問題對開發人員生產力的影響,我們投入了大量資金來修正這類問題。
如果您遇到這類問題:
刪除您的 bin
和 obj
目錄之前,請將其壓縮並加以儲存,以供稍後視需要進行診斷。 您可能只是 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_BRIDGE
, num-objects
這是這個階段所考慮的網橋物件數目,而且 num_hash_entries
是在網橋程式代碼調用期間處理的物件數目。
在 GC_MINOR
和 GC_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-v7a 和 x86。 您可以在 [項目屬性>應用程式] 索引標籤>指定裝置 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 中的位置:
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)
- 升級套件時,套件必須具有相同的簽署密鑰。
因此,假設此案例:
- 您建置應用程式並將其部署為偵錯應用程式
- 您可以變更簽署金鑰,例如將 作為發行應用程式使用(或因為您不喜歡預設提供的偵錯簽署金鑰)
- 您不需要先將其移除即可安裝應用程式,例如 > 在 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)
若是如此,則有兩個可能的原因:
.apk不提供目標裝置支援的 ABI。 例如,.apk只包含armeabi-v7a二進位檔,而目標裝置僅支援armeabi。
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。