プレイヤーが画面上で物をドラッグアンドドロップできるゲームに取り組んでいます。プレイヤーが動き回ることができるアイテムのドラッグアンドドロップイベントをシミュレートできるプライベートメソッドがあります。ドラッグする場合、実際には、タッチしたビューをそのままにして、タッチしたビューからdrawableをdrawingCacheに設定して新しいImageViewを作成し、この新しく作成したImageViewを指に沿って画面上で移動します。指を離す(ビューをドロップする)と、myLayout.remove(movingImg);
を呼び出して画面から離します。シミュレートされたドラッグイベントを開始してから、他のアイテムの1つを手動で取得すると、myLayout.remove()呼び出しでnullポインターが発生するという問題があります。これは、ログからのトレースです。
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): Java.lang.NullPointerException
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewGroup.dispatchDraw(ViewGroup.Java:2122)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewGroup.drawChild(ViewGroup.Java:2506)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewGroup.dispatchDraw(ViewGroup.Java:2123)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewGroup.drawChild(ViewGroup.Java:2506)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewGroup.dispatchDraw(ViewGroup.Java:2123)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewGroup.drawChild(ViewGroup.Java:2506)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewGroup.dispatchDraw(ViewGroup.Java:2123)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewGroup.drawChild(ViewGroup.Java:2506)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewGroup.dispatchDraw(ViewGroup.Java:2123)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.View.draw(View.Java:9032)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.widget.FrameLayout.draw(FrameLayout.Java:419)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at com.Android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.Java:1910)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewRoot.draw(ViewRoot.Java:1608)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewRoot.performTraversals(ViewRoot.Java:1329)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.view.ViewRoot.handleMessage(ViewRoot.Java:1944)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.os.Handler.dispatchMessage(Handler.Java:99)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.os.Looper.loop(Looper.Java:126)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Android.app.ActivityThread.main(ActivityThread.Java:3997)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Java.lang.reflect.Method.invokeNative(Native Method)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at Java.lang.reflect.Method.invoke(Method.Java:491)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:841)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:599)
04-06 10:37:43.610: ERROR/AndroidRuntime(23203): at dalvik.system.NativeStart.main(Native Method)
トレースは、私のアクティビティ内のどこも指していません。シミュレートされたドラッグビューでmyLayout.remove()を呼び出そうとすると、例外がスローされます。私はこの線をtry/catchで囲みましたが、それは何もしませんでした。コメントアウトしても例外は発生しませんが、明らかに私のビューが画面から削除されないため、これが問題を引き起こしている行であることを私は知っています。私はこのアプリをMotorolaxoomで構築していますが、これがデバイス固有の問題であるかどうかはわかりません。ここで何が起こっているのか誰か知っていますか?
これは、.removeView()が呼び出される場所です。
@Override
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
Log.i(myTag, "Animation End");
try {
//myLayout.removeView(simulateMovingImg); //This is the line that is throwing a null pointer
simulateMovingImg.setVisibility(View.GONE); //This is how I am currently getting around the issue
params = new LayoutParams(oneImg.getWidth(),oneImg.getHeight()); // While its moving it appears larger than normal
simulateMovingImg.setLayoutParams(params); // so I set it back to the normal size
if(whichTarget == true){
targetImg.setImageDrawable(simulateMovingImg.getDrawable()); //targetImg is one of the 'drop zones' so I set its
// drawable to make it seem like the view was 'dropped' into this zone
}else{
target1Img.setImageDrawable(simulateMovingImg.getDrawable()); // same with target1Img.
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
iAmDone = true;
}
});
これは、ImageViewを開始位置から「ドロップ」される位置に移動する変換アニメーションのAnimationListener内にあります。
AnimationEndでビュー階層を変更すると、Androidは例外を作成します。
あなたがしなければならないのはこのようにあなたの呼び出しを延期することです:
@Override
public void onAnimationEnd(Animation animation) {
new Handler().post(new Runnable() {
public void run() {
myLayout.removeView(simulateMovingImg);
}
});
}
これを試して、simulateMovingImgが存在することを確認できますか
if (myLayout.indexOfChild() >= 0)
{
myLayout.removeView(simulateMovingImg);
}
ハンドラーを避けるために、受け入れられた回答を少し変更しました(これも機能します)。
@Override
public void onAnimationEnd(Animation animation) {
imageView.post(new Runnable() {
@Override
public void run() {
layout.removeView(imageView);
}
});
}
私の推測では、これはマルチスレッドの問題だと思います。別のスレッドから画像を削除したため、内部Androidレンダーループでnullポインターが発生しているようです。Android UIフレームワークは単一ですスレッド化され、UIへのすべての変更はUIスレッドで行われる必要があります。これが発生している問題である場合は、呼び出しをUIスレッドに委任するだけです。
ここにいくつかの関連情報があります: Androidスレッド
Appcompat-v7を更新した後、この問題が発生しました。上記の依存関係の現在までの最新の安定バージョンは次のとおりです。
compile 'com.Android.support:appcompat-v7:23.2.1'