トラブルシューティングのヒント
診断情報の取得
Xamarin.Android では、さまざまなバグを調査する際にいくつかの場所を確認できます。 これには以下が含まれます。
- 診断MSBuildの出力。
- デバイスのデプロイログ。
- Androidのデバッグログの出力。
診断MSBuildの出力
診断MSBuildには、パッケージのビルドに関する追加情報を含めることができます。また、パッケージのデプロイ情報が含まれている場合もあります。
Visual Studio 内で診断 MSBuild 出力を有効にするには:
- [ツール > オプション]をクリックします。..
- 左側のツリー ビューで、[プロジェクトとソリューション>のビルドと実行] を選択します。
- 右側のパネルで、MSBuild ビルド出力の詳細ドロップダウンを[診断]に設定します
- [OK]
- パッケージから不要な要素を取り除き、再ビルドします。
- 診断出力は[出力]パネルに表示されます。
Visual Studio for Mac/OS X内で診断用 MSBuild 出力を有効にするには:
- [Visual Studio for Mac Preferences]\(Visual Studio for Mac > の基本設定\)をクリックします。..
- 左側のツリー ビューで、[プロジェクト > ビルド] を選択します。
- 右側のパネルで、ログ詳細ドロップダウンを[診断]に設定します
- [OK]
- Visual Studio for Mac を再起動します。
- パッケージから不要な要素を取り除き、再ビルドします。
- [ビルド出力] ボタンをクリックすると、診断出力が Errors Pad (パッド > エラーの表示>) 内に表示されます。
デバイスのデプロイログ
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 Debug Bridge (adb)内の setpropコマンドを使用して設定できます。
adb shell setprop PROPERTY_NAME PROPERTY_VALUE
システムプロパティはプロセスの起動時に読み取られるため、アプリケーションを起動する前に設定するか、システムプロパティの変更後にアプリケーションを再起動する必要があります。
Xamarin.Android のシステム プロパティ
Xamarin.Android では、次のシステムプロパティがサポートされています。
debug.mono.debug: 空でない文字列の場合、これは
*mono-debug*
.debug.mono.env: mono が初期化される前に、アプリケーションの起動時にエクスポートする環境変数のパイプ区切り (''|) リスト。 これにより、mono ログを制御する環境変数を設定できます。
Note
値は '|'-separated' であるため、'adb shell' コマンドは引用符のセットを削除するため、値には余分な引用符のレベルが必要です。
Note
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: ローカル参照割り当ておよび割り当て解除メッセージを出力します。
Note
これらは、非常に詳細です。 本当に必要な場合を除き、有効にしないでください。
debug.mono.trace: mono --trace
=PROPERTY_VALUE
設定を設定できます。
bin
とobj
を削除しています
Xamarin.Android は、過去に次のような状況から検出されました。
- 予期しないビルドまたはランタイムエラーが発生した。
Clean
、Rebuild
、または手動でbin
とobj
のディレクトリを削除します。- 問題は解決します。
開発者の生産性に影響を与えるため、このような問題の解決に多大な投資を行っています。
このような問題が発生した場合は、次のようになります。
bin
とobj
のディレクトリを削除する前に、必要に応じて後で診断できるようzip形式で保存します。 多くの場合、Xamarin.Android アプリケーションプロジェクトをClean
するだけで、作業内容を再度取得できます。
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メッセージ
GCコンポーネントメッセージを表示するには、debug.mono.logシステムプロパティをgc を含む値に設定します。
GCメッセージは、GCが実行されるたびに生成され、GCによって行われた作業量に関する情報を提供します。
I/monodroid-gc(12331): GC cleanup summary: 81 objects tested - resurrecting 21.
タイミング情報などの追加のGC 情報は、MONO_LOG_LEVEL
環境変数をdebug
に設定することにより生成されます。
adb shell setprop debug.mono.env MONO_LOG_LEVEL=debug
これにより、次の3つの結果を含む(多くの)追加の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までグローバル参照の制限が緩和されます。 エミュレーターでアプリケーションを実行すると、この低い制限が問題になる場合があります。そのため、インスタンスの場所を把握することは非常に便利です。
Note
グローバル参照のカウントは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
結果として、次の4つのメッセージがあります。
- グローバル参照の作成: +g+で始まる行で、作成するコードパスのスタックトレースが提供されます。
- グローバル参照の破棄: これらは -g-で始まる行であり、グローバル参照のコードパスの破棄のスタックトレースを提供する場合があります。 GCがgrefを処分する場合、スタックトレースは提供されません。
- 弱グローバル参照の作成: +w+で始まる行です。
- 弱グローバル参照の作成: -w-で始まる行です。
すべてのメッセージにおいて、grefc値は、Xamarin.Androidによって作成されたグローバル参照の数になります。一方、grefwc値は、Xamarin.Androidで作成された弱グローバル参照の数です。 ハンドルまたはobj ハンドル値はJNI handleの値であり、'/'の後の文字はハンドル値の型です。ローカル参照の場合は /L、グローバル参照の場合は/G、弱グローバル参照の場合は/Wになります。
GCプロセスの一部として、グローバル参照(+g+) が弱グローバル参照 (+w+と-g-を引き起こします)に変換され、Java側のGC が開始され、弱グローバル参照が収集されたかどうかが確認されます。 まだそれが生きている場合には、弱参照 (+g+,-w-) の周りに新しいgrefが作成されます。それ以外の場合は、弱参照が破棄されます(-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
ハンドルが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
ここで「興味深い」注意点が1つあります。4.0以前のAndroid を実行しているターゲットでは、その値はAndroidランタイムのメモリ内のJava オブジェクトのアドレスと同じになります。 (つまり、GC は動かさない保守的なコレクターであり、それらのオブジェクトへの直接参照を渡します)。したがって、+g+、+w+、-g-、+g+、-w- シーケンスの後、結果の gref は元の gref 値と同じ値になります。 これにより、ログのgrepが非常に簡単になります。
ただし、Android 4.0には移動コレクターがあり、AndroidランタイムVMオブジェクトへの直接の参照が与えられることはありません。 その結果、+g+、+w+、-g-、+g+、-w-シーケンスの後には、のgrefの値はと異なるでしょう。 オブジェクトが複数のGCの後に存在する場合には複数の値が変更されるため、インスタンスが実際に割り当てられた場所を特定するのが難しくなります。
プログラムによるクエリ
JniRuntime
オブジェクトに対してクエリを実行することによって、GREFとWREFの数を計算することができます。
Java.Interop.JniRuntime.CurrentRuntime.GlobalReferenceCount
-グローバル参照の数
Java.Interop.JniRuntime.CurrentRuntime.WeakGlobalReferenceCount
-弱参照の数
Androidのデバッグログ
Androidのデバッグログでは、表示されているランタイムエラーに関する追加のコンテキストが提供される場合があります。
浮動小数点のパフォーマンスが低下しています!
または、「デバッグビルドではリリースビルドと比べてアプリが10倍高速に実行されます!」
Xamarin.Android は、複数のデバイスABIをサポートしています。 armeabi、armeabi-v7a、そしてx86です。 [Project Properties Application]\(プロジェクト プロパティ > アプリケーション\) タブ>で、サポートされているアーキテクチャでデバイス ABI を指定できます。
デバッグビルドではすべてのABIを提供するAndroidパッケージが使用されるため、ターゲットデバイスで最も高速なABIが使用されます。
リリース ビルドには、[プロジェクトのプロパティ] タブで選択した ABI のみが含まれます。複数選択できます。
armeabiは既定のABI であり、最も広範なデバイスサポートを備えています。 ただし、armeabi ではマルチCPU デバイスとハードウェアの浮動小数点はサポートされていません。 したがって、armeabiリリースランタイムを使用するアプリは1つのコアに関連付けられ、ソフトウェアの浮動小数点を実装します。 このどちらも、アプリケーションのパフォーマンスを大幅に低下させる可能性があります。
アプリで適切な浮動小数点のパフォーマンスを必要とする場合(ゲームなど)では、armeabi-v7aABI を有効にする必要があります。 armeabi-v7aランタイムだけをサポートすることもできますが、これはarmeabiのみをサポートする古いデバイスがアプリを実行できないことを意味します。
Android SDKが見つかりませんでした
Windows 用Android SDK には、Googleから2つのダウンロードが用意されています。 .exeインストーラーを選択すると、XamarinAndroidにインストール場所を通知するレジストリキーが書き込まれます。 .zipファイルを選択して自分で解凍した場合、Xamarin.AndroidにはSDKを検索する場所がわかりません。 Visual Studio の SDK の場所を Xamarin.Android に通知するには、[ツール オプション] > Xamarin > Android 設定に移動>します。
IDEにターゲットデバイスが表示されない
アプリケーションをデバイスにデプロイしようとしたときに、[デバイスの選択]ダイアログにデプロイする先のデバイスが表示されないことがあります。 これは、Android Debug Bridgeがお休みしてしまったときに起きる場合があります。
この問題を診断するには、adb programを見つけて、次のとおり実行します。
adb devices
デバイスが存在しない場合には、Android Debug Bridgeサーバーを再起動して、デバイスが検出されるようにする必要があります。
adb kill-server
adb start-server
HTC Syncソフトウェアはadb start-server の正常な動作を妨げることがあります。 adb start-serverコマンドで開始されているポートが出力されない場合にはHTC Syncソフトウェアを終了し、adbサーバーを再起動してください。
指定された実行可能タスク「Keytool」を実行できませんでした。
これは、Java SDKのbinディレクトリが配置されているディレクトリが、PATHに含まれていないことを意味します。 インストールガイドの手順に従っていたことを確認します。
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マニフェスト]タブをクリックします。
- パッケージ名の欄を更新します。
- "No AndroidManifest.xml found. クリックして追加します。"、リンクをクリックし、[パッケージ名] フィールドを更新します。
- Visual Studio for Mac 内:
- プロジェクト > の [オプション] を右クリックします。
- [ビルド/Android アプリケーション]セクションに移動します。
- 「.」が含まれるようにパッケージ名の欄を変更します。
パッケージのインストール時のINSTALL_FAILED_MISSING_SHARED_LIBRARY
ここで言う「共有ライブラリ」 は、ネイティブの共有ライブラリ (libfoo.so) ファイルではありません。Google Mapsなど、ターゲットデバイスに個別にインストールする必要があるライブラリを指します。
Android パッケージでは、<uses-library/>
要素に必要な共有ライブラリを指定します。 必要なライブラリがターゲット デバイスに存在しない場合 (たとえば//uses-library/@android:required
、既定値は true)、パッケージのインストールはINSTALL_FAILED_MISSING_SHARED_LIBRARYで失敗します。
必要な共有ライブラリを特定するには、生成されたAndroidManifest.xml ファイル (obj\Debug\android\AndroidManifest.xml など) を表示し、要素を<uses-library/>
探します。 <uses-library/>
要素は、プロジェクトの Properties\AndroidManifest.xml ファイルおよび UsesLibraryAttribute カスタム属性を使用して手動で追加できます。
たとえば、アセンブリ参照をMono.GoogleMap.dll に追加すると、Google Maps共有ライブラリの<uses-library/>
が暗黙的に追加されます。
パッケージのインストール時のINSTALL_FAILED_UPDATE_INCOMPATIBLE
Androidパッケージには、次の3つの要件があります。
- 「.」が含まれている必要があります。(前のエントリを参照)
- 一意の文字列パッケージ名を持つ必要があります(したがってAndroid app名には逆tld則が適用され、例えばChrome appの場合にはcom.android.chromeとなります)。
- パッケージをアップグレードするときは、パッケージの署名キーが同じである必要があります。
ここで次のシナリオを考えてみましょう。
- アプリをデバッグアプリとしてビルド&デプロイします。
- そして、たとえばリリースアプリとして使用する場合に(または、既定で提供されるデバッグ署名キーが気に入らない場合)、署名キーを変更します。
- 最初にアプリを削除せずにインストールします 。たとえば、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パッケージをインストールすると、ユーザーID(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@
Uadb uninstall -k
Standard Editionしないでください。これにより、アプリケーション データが保持され、ターゲット デバイス上で競合する 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)
この問題の原因は2つ考えられます。
.apkに、ターゲットデバイスでサポートされているABI が用意されていません。 たとえば、.apkにarmeabi-v7aバイナリのみが含まれ、ターゲットデバイスはarmeabiのみをサポートしている場合です。
Androidのバグ。 このような場合には、アプリをアンインストールし、祈り、そしてアプリを再インストールしましょう。
(1)を修正するには、プロジェクトのオプションとプロパティを編集し 必要なABI のサポートをサポートされている ABIの一覧に追加します。 どのABI を追加する必要があるかを判断するには、ターゲットデバイスに対して次のadb コマンドを実行します。
adb shell getprop ro.product.cpu.abi
adb shell getprop ro.product.cpu.abi2
出力には、プライマリ(セカンダリを持つ場合もあります)のABIが含まれます。
$ adb shell getprop | grep ro.product.cpu
[ro.product.cpu.abi2]: [armeabi]
[ro.product.cpu.abi]: [armeabi-v7a]
OutPath プロパティがプロジェクト "MyApp.csproj" に設定されていません
これは一般に、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
はjava.util.Mapを実装するものではなく(Dictionary<string, object>
インスタンスを参照する)mono.android.runtime.JavaObject
インスタンスであるため、次の例外が発生します。
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)
回避策は、"内部" 型の型ではなく、指定された System.Collections.Generic
Java コレクション型を使用することです。 これにより、インスタンスをマーシャリングするときに、適切なJavaの型が得られます。 (次のコードは、gref の有効期間を短縮するために必要以上に複雑です。gref の有効期間が心配にならない場合は、s/Dictionary/JavaDictionary/g
元のコードs/List/JavaList/g
を変更することが簡単になります)。
// 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 }
);
}
}
想定外のNullReferenceExceptions
Android デバッグ ログでは、"発生できない" NullReferenceException がメンションされたり、アプリが終了する直前に Mono for Android ランタイム コードから取得されたりすることがあります。
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
上記の例 (これはバグ685215に起因します) では、Android.Graphics.Point インスタンスの作成が多すぎるという問題があります。この特定のバグの修正の一覧については、コメント 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デバイス上でクラッシュする
AOT+LLVMでビルドしたアプリをx86ベースのデバイスにデプロイすると、次のような例外が表示されることがあります。
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を無効にすることです。