Tipy na řešení potíží

Získání diagnostických informací

Xamarin.Android má několik míst, kde se můžete podívat při sledování různých chyb. Tady jsou některé z nich:

  1. Výstup nástroje MSBuild diagnostiky
  2. Protokoly nasazení zařízení
  3. Výstup protokolu ladění Androidu

Výstup nástroje MSBuild diagnostiky

Nástroj MSBuild diagnostiky může obsahovat další informace týkající se sestavení balíčku a může obsahovat některé informace o nasazení balíčku.

Povolení výstupu nástroje MSBuild diagnostiky v sadě Visual Studio:

  1. Klikněte na Možnosti nástrojů > ...
  2. V zobrazení stromu vlevo vyberte Projekty a řešení > sestavení a spuštění.
  3. Na pravém panelu nastavte rozevírací seznam podrobností výstupu sestavení NÁSTROJE MSBuild na Diagnostiku.
  4. Klikněte na tlačítko OK.
  5. Vyčistěte a znovu sestavte balíček.
  6. Výstup diagnostiky je viditelný na panelu Výstup.

Povolení výstupu nástroje MSBuild diagnostiky v rámci Visual Studio pro Mac/OS X:

  1. Klikněte na Visual Studio pro Mac > Předvolby...
  2. V zobrazení levého stromu vyberte Sestavení projektů > .
  3. Na pravém panelu nastavte rozevírací seznam Podrobností protokolu na Diagnostiku.
  4. Klikněte na tlačítko OK.
  5. Restartování Visual Studio pro Mac
  6. Vyčistěte a znovu sestavte balíček.
  7. Diagnostický výstup se zobrazí v části Chyby (zobrazit > chyby) > kliknutím na tlačítko Výstup sestavení.

Protokoly nasazení zařízení

Povolení protokolování nasazení zařízení v sadě Visual Studio:

  1. Možnosti nástrojů > ...>
  2. V levém stromovém zobrazení vyberte Xamarin > Android Nastavení
  3. Na pravém panelu povolte protokolování ladění rozšíření [X] (zapisuje monodroid.log na plochu).
  4. Zprávy protokolu se zapisují do souboru monodroid.log na ploše.

Visual Studio pro Mac vždy zapisuje protokoly nasazení zařízení. Jejich zatěžování je o něco obtížnější; Soubor protokolu AndroidUtils se vytvoří každý den a čas, kdy dojde k nasazení, například: AndroidTools-2012-10-24_12-35-45.log.

  • Ve Windows jsou soubory protokolu zapsány do %LOCALAPPDATA%\XamarinStudio-{VERSION}\Logs.
  • V OS X jsou soubory protokolu zapsány do $HOME/Library/Logs/XamarinStudio-{VERSION}.

Výstup protokolu ladění androidu

Android zapíše mnoho zpráv do protokolu ladění Androidu. Xamarin.Android používá vlastnosti systému Android k řízení generování dalších zpráv do protokolu ladění Androidu. Vlastnosti systému Android je možné nastavit pomocí příkazu setprop v rámci mostu Android Debug Bridge (adb):

adb shell setprop PROPERTY_NAME PROPERTY_VALUE

Systémové vlastnosti se čtou během spouštění procesu, a proto musí být buď nastaveny před spuštěním aplikace, nebo musí být aplikace restartována po změně systémových vlastností.

Vlastnosti systému Xamarin.Android

Xamarin.Android podporuje následující systémové vlastnosti:

  • debug.mono.debug: Pokud neprázdný řetězec, je to ekvivalentní *mono-debug*.

  • debug.mono.env: Seznam proměnných prostředí oddělených kanálem ('|) pro export během spouštění aplikace před inicializováním mono. To umožňuje nastavit proměnné prostředí, které řídí mono protokolování.

    Poznámka:

    Vzhledem k tomu, že hodnota je| oddělená od sebe, musí mít hodnota další úroveň uvozovek, protože příkaz "adb shell" odebere sadu uvozovek.

    Poznámka:

    Hodnoty systémových vlastností androidu nesmí být delší než 92 znaků.

    Příklad:

    adb shell setprop debug.mono.env "'MONO_LOG_LEVEL=info|MONO_LOG_MASK=asm'"
    
  • debug.mono.log: Seznam komponent oddělených čárkami (','), které by měly tisknout další zprávy do protokolu ladění Androidu. Ve výchozím nastavení není nic nastavené. Mezi komponenty patří:

    • all: Print all messages
    • gc: Tisk zpráv souvisejících s GC.
    • gref: Přidělení odkazu a zrušení přidělení odkazu (slabý, globální) tisk.
    • lref: Vytiskněte místní přidělení odkazů a zprávy o zrušení přidělení.

    Poznámka:

    Jedná se o velmi podrobné. Nepovolujte, pokud opravdu nepotřebujete.

  • debug.mono.trace: Povolí nastavení mono --trace=PROPERTY_VALUE .

Odstranění a odstranění binobj

Xamarin.Android utrpěl v minulosti situaci, jako je:

  • Dochází k podivné chybě sestavení nebo modulu runtime.
  • Vy nebo Rebuildručně odstraníte Cleansvé bin adresáře a obj adresáře.
  • Problém zmizí.

Výrazně investujeme do řešení problémů, jako jsou tyto problémy z důvodu jejich dopadu na produktivitu vývojářů.

Pokud se vám stane problém, jako je tento:

  1. Udělejte si myšlenkovou poznámku. Jaká byla poslední akce, která váš projekt dostala do tohoto stavu?
  2. Uložte aktuální protokol sestavení. Zkuste sestavení vytvořit znovu a zaznamenat diagnostický protokol sestavení.
  3. Odešlete zprávu o chybě.

Před odstraněním adresářů bin je obj zazipujte a v případě potřeby je uložte pro pozdější diagnostiku. Pravděpodobně můžete jenom Clean projekt aplikace Xamarin.Android, abyste mohli znovu začít pracovat.

Xamarin.Android nemůže přeložit System.ValueTuple

K této chybě dochází kvůli nekompatibilitě se sadou Visual Studio.

  • Visual Studio 2017 Update 1 (verze 15.1 nebo starší) je kompatibilní pouze se system.ValueTuple NuGet 4.3.0 (nebo starší).

  • Visual Studio 2017 Update 2 (verze 15.2 nebo novější) je kompatibilní pouze se System.ValueTuple NuGet 4.3.1 (nebo novějším).

Zvolte správný NuGet System.ValueTuple, který odpovídá vaší instalaci sady Visual Studio 2017.

Zprávy GC

Zprávy součásti GC lze zobrazit nastavením debug.mono.log systémové vlastnosti na hodnotu, která obsahuje gc.

Zprávy GC se generují při každém spuštění GC a poskytují informace o tom, kolik práce GC udělal:

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

Další informace o GC, jako jsou informace o časování, lze vygenerovat nastavením MONO_LOG_LEVEL proměnné prostředí na debug:

adb shell setprop debug.mono.env MONO_LOG_LEVEL=debug

Výsledkem bude (spousta) dalších mono zpráv, včetně těchto tří důsledků:

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 Ve zprávě je počet objektů mostu, num-objects které tento průchod zvažuje, a num_hash_entries je počet objektů zpracovaných během tohoto vyvolání kódu mostu.

GC_MINORGC_MAJOR Ve zprávách total je doba, po kterou se svět pozastaví (nespouštějí se žádná vlákna), zatímco bridge doba potřebná v kódu pro zpracování mostu (který se zabývá virtuálním počítačem Java). Svět není pozastaven, když probíhá zpracování mostu.

Obecně platí, že čím větší je hodnota num_hash_entries, tím více času bridge bude trvat kolekce a tím větší total bude čas strávený shromažďováním.

Globální referenční zprávy

Chcete-li povolit protokolování protokolu GREF (Global Reference Loggig), musí systémová vlastnost debug.mono.log obsahovat gref, například:

adb shell setprop debug.mono.log gref

Xamarin.Android používá globální odkazy na Android k poskytování mapování mezi instancemi Java a přidruženými spravovanými instancemi, protože při vyvolání metody Javy je potřeba instanci Javy poskytnout javě.

Emulátory Androidu bohužel umožňují najednou existovat pouze 2000 globálních odkazů. Hardware má mnohem vyšší limit 52000 globálních odkazů. Nižší limit může být problematický při spouštění aplikací v emulátoru, takže znalost , odkud instance pochází, může být velmi užitečná.

Poznámka:

Globální počet odkazů je interní pro Xamarin.Android a neobsahuje (a nemůže) zahrnovat globální odkazy odebrané jinými nativními knihovnami načtenými do procesu. Jako odhad použijte globální počet odkazů.

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

Existují čtyři zprávy, které jsou důsledkem:

  • Globální vytváření odkazů: jedná se o řádky začínající na +g+ a poskytnou trasování zásobníku pro cestu k vytvoření kódu.
  • Globální zničení odkazu: jedná se o řádky začínající znakem -g- a mohou poskytnout trasování zásobníku pro cestu kódu, která dispoziuje globální odkaz. Pokud se GC dispoziuje gref, nezobrazí se trasování zásobníku.
  • Slabé vytvoření globálního odkazu: jedná se o řádky začínající na +w+ .
  • Slabé globální referenční zničení: jedná se o linie, které začínají - w- .

Ve všech zprávách je hodnota grefc počtem globálních odkazů, které Xamarin.Android vytvořil, zatímco hodnota grefwc je počet slabých globálních odkazů, které Xamarin.Android vytvořil. Hodnota popisovače nebo obj-handle je hodnota popisovače JNI a znak za ' /je typ hodnoty popisovače: /L pro místní odkaz, /G pro globální odkazy a /W pro slabé globální odkazy.

V rámci procesu GC se globální odkazy (+g+) převedou na slabé globální odkazy (což způsobuje chybu +w+ a -g-), spustí se globální katalog na straně Javy a pak se kontroluje slabý globální odkaz, aby se zjistilo, jestli se shromáždil. Pokud je stále naživu, vytvoří se kolem slabého odkazu (+g+, -w-), jinak se slabý odkaz zničí (-w).

Instance Java se vytvoří a zabalí pomocí 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`

Probíhá 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

Objekt je stále aktivní, protože popisovač != null

wref se vrátil zpět na 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

Objekt je mrtvý, protože popisovač == null

wref se uvolní, nevytvořil se nový 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

Zde je jedna "zajímavá" vráska: na cílech, na kterých běží Android před 4,0, je hodnota gref rovna adrese objektu Java v paměti modulu Android Runtime. (To znamená, že GC je nehýbající se, konzervativní, kolektor a podává přímé odkazy na tyto objekty.) Proto za sekvenci +g+, +w+, -g+, -w- bude výsledná hodnota gref mít stejnou hodnotu jako původní hodnota gref. Díky tomu je grepping přes protokoly poměrně jednoduchý.

Android 4.0 ale má pohyblivý kolektor a už nemá přímé odkazy na objekty virtuálních počítačů s Android runtime. V důsledku toho se za sekvencí +g+, +w+, -g+, -w- bude hodnota gref lišit. Pokud objekt přežije více GCS, přejde o několik hodnot gref, což znesnadní určení, odkud byla instance skutečně přidělena.

Dotazování prostřednictvím kódu programu

Dotazováním objektu JniRuntime můžete dotazovat počty GREF i WREF.

Java.Interop.JniRuntime.CurrentRuntime.GlobalReferenceCount – Globální referenční počet

Java.Interop.JniRuntime.CurrentRuntime.WeakGlobalReferenceCount - Slabý počet odkazů

Protokoly ladění Androidu

Protokoly ladění Androidu můžou poskytovat další kontext týkající se chyb modulu runtime, které se vám zobrazují.

Výkon s plovoucí desetinou čárkou je hrozný!

Případně můžete použít příkaz "Moje aplikace běží 10krát rychleji s buildem Debug než s buildem vydané verze!"

Xamarin.Android podporuje více abI zařízení: armeabi, armeabi-v7a a x86. Rozhraní ABI zařízení je možné zadat na kartě Aplikace vlastností > projektu podporované architektury>.

Ladicí buildy používají balíček Androidu, který poskytuje všechny abI, a proto pro cílové zařízení použije nejrychlejší ABI.

Buildy vydané verze budou obsahovat pouze abI vybrané na kartě Vlastnosti projektu. Můžete vybrat více než jednu.

Armeabi je výchozí ABI a má nejširší podporu zařízení. Armeabi ale nepodporuje zařízení s více procesory a hardwarovou plovoucí desetinou čárku amont další věci. Aplikace využívající modul runtime armeabi release se proto sváže s jedním jádrem a budou používat implementaci s soft-float. Obě tyto možnosti můžou přispět k výrazně pomalejšímu výkonu vaší aplikace.

Pokud vaše aplikace vyžaduje slušný výkon s plovoucí desetinou čárkou (např. hry), měli byste povolit armeabi-v7a ABI. Možná budete chtít podporovat pouze modul runtime armeabi-v7a , i když to znamená, že starší zařízení, která podporují jenom armeabi , nebudou moct vaši aplikaci spustit.

Nepodařilo se najít sadu Android SDK.

Google pro Android SDK pro Windows má k dispozici 2 soubory ke stažení. Pokud zvolíte instalační program .exe, zapíše klíče registru, které říkají Xamarin.Android, kde byl nainstalovaný. Pokud zvolíte .zip soubor a rozbalíte ho sami, Xamarin.Android neví, kde hledat sadu SDK. Xamarin.Android, kde je sada SDK v sadě Visual Studio, poznáte tak, že přejdete na nástroje > Možnosti > Xamarin > Androidu Nastavení:

Android SDK Location in Xamarin Android Settings

Integrované vývojové prostředí (IDE) nezobrazuje cílové zařízení

Někdy se pokusíte nasadit aplikaci do zařízení, ale zařízení, do kterého chcete nasadit, se v dialogovém okně Vybrat zařízení nezobrazí. K tomu může dojít, když se ladicího mostu Androidu rozhodne jít na dovolenou.

Pokud chcete tento problém diagnostikovat, vyhledejte program adb a spusťte:

adb devices

Pokud vaše zařízení není k dispozici, musíte restartovat server Mostu pro ladění Androidu, aby bylo možné zařízení najít:

adb kill-server
adb start-server

Software HTC Sync může zabránit správnému fungování start-serveru adb. Pokud příkaz start-server adb nevytiskne port, na kterém se spouští, ukončete software HTC Sync a zkuste restartovat server adb.

Zadaný spustitelný soubor úlohy keytool nelze spustit.

To znamená, že vaše cesta neobsahuje adresář, ve kterém se nachází adresář bin sady Java SDK. Zkontrolujte, že jste postupovali podle těchto kroků v průvodci instalací .

monodroid.exe nebo aresgen.exe ukončeny kódem 1

Chcete-li ladit tento problém, přejděte do sady Visual Studio a změňte úroveň podrobností nástroje MSBuild, chcete-li to provést, vyberte: Tools > Options > Project and Solutions > Build and Run > MSBuild Project Build Output Verbosity a set this value to Normal.

Znovu sestavte a zkontrolujte podokno Výstup v sadě Visual Studio, které by mělo obsahovat úplnou chybu.

Na zařízení není dostatek úložného prostoru pro nasazení balíčku.

K tomu dochází, když emulátor nespustíte ze sady Visual Studio. Při spuštění emulátoru mimo Visual Studio je potřeba předat -partition-size 512 možnosti, například

emulator -partition-size 512 -avd MonoDroid

Ujistěte se, že používáte správný název simulátoru, tj. název, který jste použili při konfiguraci simulátoru.

INSTALL_FAILED_INVALID_APK při instalaci balíčku

Názvy balíčků pro Android musí obsahovat tečku (.). Upravte název balíčku tak, aby obsahoval tečku.

  • V sadě Visual Studio:
    • Klikněte pravým tlačítkem myši na vlastnosti projektu > .
    • Na levé straně klikněte na kartu Manifest androidu.
    • Aktualizujte pole Název balíčku.
      • Pokud se zobrazí zpráva "Nebyly nalezeny žádné AndroidManifest.xml. Kliknutím přidáte položku.", klikněte na odkaz a potom aktualizujte pole Název balíčku.
  • V Visual Studio pro Mac:
    • Klikněte pravým tlačítkem na možnosti projektu > .
    • Přejděte do části Sestavení nebo aplikace pro Android.
    • Změňte pole Název balíčku tak, aby obsahovalo ".".

INSTALL_FAILED_MISSING_SHARED_LIBRARY při instalaci balíčku

Sdílená knihovna v tomto kontextu není nativním sdíleným souborem (libfoo.so). Jedná se o knihovnu, která musí být nainstalovaná samostatně na cílovém zařízení, například Google Mapy.

Balíček Pro Android určuje, které sdílené knihovny jsou požadovány s prvkem <uses-library/> . Pokud požadovaná knihovna na cílovém zařízení není (např. //uses-library/@android:requiredje pravda, což je výchozí hodnota), instalace balíčku selže s INSTALL_FAILED_MISSING_SHARED_LIBRARY.

Pokud chcete zjistit, které sdílené knihovny jsou potřeba, prohlédněte si vygenerovaný soubor AndroidManifest.xml (např. obj\Debug\android\AndroidManifest.xml) a vyhledejte <uses-library/> prvky. <uses-library/>Elementy lze přidat ručně do souboru Properties\AndroidManifest.xml projektu a prostřednictvím vlastního atributu UsesLibraryAttribute.

Například přidání odkazu na sestavení Mono.Android.Google Mapy.dll implicitně přidá pro Mapy sdílenou <uses-library/> knihovnu Google.

INSTALL_FAILED_UPDATE_INCOMPATIBLE při instalaci balíčku

Balíčky pro Android mají tři požadavky:

  • Musí obsahovat "." (viz předchozí položka)
  • Musí mít jedinečný název balíčku řetězce (proto se v názvech aplikací pro Android používá konvence reverzního tldu, e.g. com.android.chrome pro aplikaci pro Chrome).
  • Při upgradu balíčků musí mít balíček stejný podpisový klíč.

Představte si tedy tento scénář:

  1. Sestavíte a nasadíte aplikaci jako ladicí aplikaci.
  2. Podpisový klíč změníte, například tak, aby se používal jako aplikace vydané verze (nebo protože se vám nelíbí podpisový klíč pro ladění, který jste zadali jako výchozí).
  3. Aplikaci nainstalujete bez toho, abyste ji napřed odebrali, například ladit > spustit bez ladění v sadě Visual Studio.

Pokud k tomu dojde, instalace balíčku selže s chybou INSTALL_FAILED_UPDATE_INCOMPATIBLE, protože název balíčku se během podepisování klíče nezměnil. Protokol ladění Androidu bude obsahovat také zprávu podobnou této:

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

Pokud chcete tuto chybu opravit, před opětovnou instalací zcela odeberte aplikaci ze zařízení.

INSTALL_FAILED_UID_CHANGED při instalaci balíčku

Když je nainstalovaný balíček Androidu, přiřadí se mu ID uživatele (UID). Někdy, z aktuálně neznámých důvodů, při instalaci přes již nainstalovanou aplikaci se instalace nezdaří s 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()

Chcete-li tento problém vyřešit, zcela odinstalujte balíček Pro Android buď instalací aplikace z grafického uživatelského rozhraní cíle androidu, nebo pomocí adb:

$ adb uninstall @PACKAGE_NAME@

NEPOUŽÍVEJTEadb uninstall -k, protože tím se zachová data aplikace, a tím se zachová konfliktní UID na cílovém zařízení.

Vydání aplikací se nedaří spustit na zařízení

Bude výstup protokolu ladění androidu obsahovat zprávu podobnou této:

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)

Pokud ano, existují dvě možné příčiny:

  1. .apk neposkytuje ABI, kterou cílové zařízení podporuje. Například .apk obsahuje pouze binární soubory armeabi-v7a a cílové zařízení podporuje pouze armeabi.

  2. Chyba Androidu. Pokud tomu tak je, odinstalujte aplikaci, pokračte prsty a aplikaci znovu nainstalujte.

Pokud chcete opravit (1), upravte možnosti nebo vlastnosti projektu a přidejte podporu požadovaného ABI do seznamu podporovaných abI. Pokud chcete zjistit, který ABI potřebujete přidat, spusťte na cílovém zařízení následující příkaz adb:

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

Výstup bude obsahovat primární (a volitelné sekundární) identifikátory ABI.

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

Vlastnost OutPath není nastavená pro projekt MyApp.csproj.

Obvykle to znamená, že máte počítač HP a proměnná prostředí "Platforma" je nastavená na něco jako MCD nebo HPD. To je v konfliktu s MSBuild Platform vlastnost, která je obecně nastavena na "Any CPU" nebo "x86". Tuto proměnnou prostředí budete muset ze svého počítače odebrat, aby nástroj MSBuild mohl fungovat:

  • >> Ovládací panely systémových pokročilých > proměnných prostředí

Restartujte Visual Studio nebo Visual Studio pro Mac a zkuste znovu sestavit. Věci by teď měly fungovat podle očekávání.

java.lang.ClassCastException: mono.android.runtime.JavaObject nelze přetypovat na...

Xamarin.Android 4.x správně nezařazuje vnořené obecné typy správně. Představte si například následující kód jazyka C#, který používá SimpleExpandableListAdapter:

// 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 }
);

Problémem je, že Xamarin.Android nesprávně zařazuje vnořené obecné typy. Zařazuje se List<IDictionary<string, object>> do java.lang.ArrrayList, ale ArrayList obsahuje mono.android.runtime.JavaObject instance (které odkazují na Dictionary<string, object> instance) místo něčeho, co implementuje java.util.Map, což vede k následující výjimce:

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)

Alternativním řešením je použít zadané typy kolekcí Java místo System.Collections.Generic typů pro "vnitřní" typy. Výsledkem bude odpovídající typy Javy při zařazováníinstancích (Následující kód je složitější, než je nutné, aby se snížila životnost gref. Můžete ho zjednodušit tak, že původní kód změníte tak, že s/Dictionary/JavaDictionary/g se nebudete starat o s/List/JavaList/g životnosti 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 }
        );
    }
}

Neočekávané hodnoty NullReferenceExceptions

Někdy se v protokolu ladění Androidu zmíní nullReferenceExceptions, které "nelze provést" nebo pocházejí z kódu modulu runtime Mono pro Android krátce před tím, než aplikace zemře:

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)

nebo

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)

K tomu může dojít, když se Modul runtime Androidu rozhodne proces přerušit, což se může stát z libovolného počtu důvodů, včetně dosažení limitu GREF cíle nebo nějakého "špatného" použití JNI.

Pokud chcete zjistit, jestli se jedná o tento případ, zkontrolujte v protokolu ladění Androidu zprávu z vašeho procesu, která se podobá následujícímu:

E/dalvikvm(  123): VM aborting

Přerušení kvůli vyčerpání globálních odkazů

Vrstva JNI modulu Runtime pro Android podporuje pouze omezený počet odkazů na objekt JNI, které mají být platné v libovolném časovém okamžiku. Když se tento limit překročí, věci se přeruší.

Limit GREF (globální referenční dokumentace) je 2000 odkazů v emulátoru a přibližně 52000 odkazů na hardware.

Víte, že začínáte vytvářet příliš mnoho grefů, když se v protokolu ladění Androidu zobrazí například zprávy:

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

Když dosáhnete limitu GREF, vytiskne se například následující zpráva:

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

V předchozím příkladu (který mimochodem pochází z chyby 685215) je problém, že se vytváří příliš mnoho instancí Android.Graphics.Point. Seznam oprav pro tuto konkrétní chybu najdete v komentáři č. 2 .

Obvykle je užitečné najít, který typ má příliš mnoho přidělených instancí – Android.Graphics.Point ve výše uvedeném výpisu paměti – pak zjistí, kde se vytvoří ve zdrojovém kódu, a odpovídajícím způsobem je odstraní (aby se zkrátila jejich životnost objektu Java). To není vždy vhodné (#685215 je vícevláknové, takže triviální řešení se vyhne volání Dispose), ale je to první věc, kterou je potřeba vzít v úvahu.

Protokolování GREF můžete povolit, abyste viděli, kdy jsou vytvořené grefy a kolik jich existuje.

Přerušení kvůli neshodě typů JNI

Pokud kód JNI ručně zařadíte, je možné, že se typy nebudou správně shodovat, například pokud se pokusíte vyvolat java.lang.Runnable.run typ, který neimplementuje java.lang.Runnable. V takovém případě se v protokolu ladění Androidu zobrazí podobná zpráva:

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

Podpora dynamického kódu

Dynamický kód se nekompiluje

Pokud chcete v aplikaci nebo knihovně používat dynamický jazyk C#, musíte do projektu přidat System.Core.dll, Microsoft.CSharp.dll a Mono.CSharp.dll.

V buildu vydané verze dojde k chybě MissingMethodException pro dynamický kód za běhu.

  • Je pravděpodobné, že projekt aplikace nemá odkazy na System.Core.dll, Microsoft.CSharp.dll nebo Mono.CSharp.dll. Ujistěte se, že jsou na tato sestavení odkazována.

    • Mějte na paměti, že dynamický kód vždy stojí. Pokud potřebujete efektivní kód, zvažte použití dynamického kódu.
  • V první verzi Preview byly tato sestavení vyloučena, pokud nejsou explicitně používány kódem aplikace typy v každém sestavení. Alternativní řešení najdete v následujících tématech: http://lists.ximian.com/pipermail/mo...il/009798.html

Projekty vytvořené s chybovým ukončením AOT+LLVM na zařízeních x86

Při nasazování aplikace vytvořené pomocí AOT+LLVM na zařízeních s platformou x86 se může zobrazit chybová zpráva o výjimce podobná této:

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)

Jedná se o známý problém – alternativním řešením je zakázat LLVM.