2

GlSurfaceView とレンダラーを使用するアプリケーションがあります。ユーザーが [戻る] ボタンを使用してアプリケーションを終了したときに myActivity.finish(); を呼び出すように設定しました。

これは問題なく、アクティビティが onStop() および onDestroy(); への呼び出しを取得していることがわかります。

アプリは最初の実行時は正常に動作しますが、その後実行すると、motionEvents に問題が発生しました。

モーション イベントをプールのキューに入れ、次のように適切なタイミングでレンダラーがプールにアクセスできるようにすることで、モーション イベントを処理します。

try
    {
        //Get the history first
        int hist = event.getHistorySize();
        if (hist > 0)
        {
            //Oldest is first in the list. (I think).
            for (int i=0;i <hist; i++)
            {
                InputObject input = inputObjectPool.take();
                input.useEventHistory(event, i);
                defRenderer.feedInput(input);
            }
        }

        //The current one still needs to be added
        InputObject input = inputObjectPool.take();
        input.useMotionEvent(event);
        defRenderer.feedInput(input);
    }

そしてレンダラーで:

            synchronized (inputQueueMutex) 
    {
        ArrayBlockingQueue<InputObject> inputQueue = this.inputQueue;
        while (!inputQueue.isEmpty()){try
            {
                InputObject input = inputQueue.take();

                if (input.eventType == InputObject.EVENT_TYPE_TOUCH)
                {
                    screenManager.processMotionEvent(input); 
                }
                else if (input.eventType == InputObject.EVENT_TYPE_KEY)
                {
                    screenManager.processKeyPress(input);
                }

                input.returnToPool();
            }
            catch (InterruptedException ie)
            {
                DLog.defError("Interrupted blocking on input queue.", ie);
            }
        }
    }

上記のコードでわかるように、これらのモーション イベントを ScreenManager に渡します。これは基本的に、レンダリングするいくつかの「シーン」を持つ方法です。これは、アプリケーションを初めて実行したときにうまく機能し、画面はモーションタッチを現時点で単純な正方形の動きに解釈します.

ただし、アプリケーションを 2 回目に実行すると、正方形が画面にうまく描画されますが、モーション イベントは何もしません。

モーション イベントを追跡しましたが、それらは「新しい」レンダラーに渡されますが、モーション イベントが古い画面に渡されているようです。というか、画面上の古いオブジェクトに。これは、 onCreate() メソッドの私のコードのように混乱しています。

//Set up the renderer and give it to the SurfaceView
    defRenderer = new DefRenderer();
    defView = new DefView(this);
    defView.setRenderer(defRenderer);

    //Set out content to the surface view.
    setContentView(defView);

    //Set up the input queue
    createInputObjectPool();

OnCreate は、アプリの初回実行時と 2 回目の実行時に呼び出されます (そしてアプリが破棄されました!) 画面は defRenderer で新しく作成され、新しい defView に渡されます。

アプリが完全に作り直されたので、どのようにデータが defRenderer に残って motionEvents を受け取ることができるのか非常に混乱しています。

ここで私が見逃している明らかなことが起こっていますか? onDestroy が呼び出されると、アプリは完全に逆参照されるため、その痕跡は残りません。これは真実ではありませんか?new Renderer(); を呼び出すと何とかなります。古いものを参照していますか?

私は実際に何が起こっているのか途方に暮れています。特に、このアプリは私が書いた別のアプリの基本的なコピーであり、完全に正常に動作します!

編集:

少し実験した後、モーション イベントが実際には、MotionEvents のリスナーとして登録されている古い ScrollPanel (私が作成したオブジェクト..) に送信されることがわかりました (リスナーとは、私自身の実装を意味します..)。私はこれらのために独自のイベントシステムを次のように作成しました:

public interface TouchSource 
public static final int TYPE_TOUCHDOWN = 0;
public static final int TYPE_TOUCHDRAG = 1;
public static final int TYPE_TOUCHCLICK = 2;

public Vector<TouchListener> listeners = new Vector<TouchListener>();

public void addTouchListener(TouchListener listener);
public void removeTouchListener(TouchListener listener);

public void touchOccured(int type, int xPos, int yPos);

}

そしてリスナーインターフェース:

public interface TouchListener 
public boolean touchDownOccured(int xPos, int yPos);
public boolean touchDragOccured(int xPos, int yPos);
public boolean touchClickOccured(int xPos, int yPos);

そのため、Screen は touchSource を実装し、リスナーのリストを持っています。現在、Screen currentScreen = new Screen(); によってリメイクされていますが、OnCreate(); で呼び出されます。マネージャーのこのリスナーのリストには、まだ古い ScrollPanel が入力されていますか?

これはどのように?明らかな何かが明らかに欠けています。どういうわけか、リスナーのリストは何らかの理由で静的であり、アプリが完全に作り直されているにもかかわらず逆参照されていませんか?

4

1 に答える 1

0

あなたが直面している問題は、元のモーションイベントがフレームワークによって返された後にリサイクルされる (プールに返される) という事実と関係があるのではないかと思いonMotionEvent()ます。

InputObjects の使用方法から、イベント データをコピーせずに、元のモーション イベントへの参照を保持している可能性があると思います。

現在使用している場所をすぐに使用してみて(これによりコピーが作成されます)、これにより奇妙な動作がなくなるかどうかを確認してくださいMotionEvent.obtain(event)event当然、これが機能する場合、それらのコピーを使い終わった後、最終的にそれらのコピーを recycle() する必要があります。recycle()ただし、元のモーション イベントは呼び出さないでください。

乾杯、アート。

于 2011-05-10T23:29:45.083 に答える