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,这基本上是我渲染多个“场景”的方式。这在我第一次运行应用程序时运行良好,屏幕将我的动作解释为此刻一个简单正方形的移动。

然而,我第二次运行该应用程序时,正方形被很好地绘制到屏幕上,但是运动事件什么也不做。

我跟踪了运动事件,虽然它们被提供给“新”渲染器,但它似乎将运动事件提供给旧屏幕。或者更确切地说是屏幕上的一个旧对象。这很令人困惑,因为我在 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 在我的应用程序第一次和第二次运行时都被调用(并且应用程序被破坏了!)屏幕在 defRenderer 中被新建,并被赋予新的 defView。

当应用程序完全重新制作时,我很困惑数据如何保留在 defRenderer 中以接收 motionEvents。

我在这里想念什么明显的事情吗?我原以为当调用 onDestroy 时,应用程序将被完全取消引用,因此不会留下任何痕迹。这不是真的吗?当我调用 new Renderer(); 它是在引用一个旧的吗?

我不知道到底发生了什么。特别是因为这个应用程序是我编写的另一个应用程序的基本副本,它工作得很好!

编辑:

经过少量实验后,我发现运动事件实际上是转到一个旧的 ScrollPanel(我制作的一个对象..),它被注册为 MotionEvents 的侦听器(我所说的侦听器是指我自己的实现..)。我为这些创建了自己的事件系统,如下所示:

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 回答