我有一个使用 GlSurfaceView 和渲染器的应用程序。我已将其设置为当用户通过后退按钮退出应用程序时调用 myActivity.finish();
很好,我可以看到 Activity 正在调用 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,这基本上是我渲染多个“场景”的方式。这在我第一次运行该应用程序时运行良好,此时屏幕将我的 Action 触摸解释为一个简单正方形的移动。
然而,我第二次运行该应用程序时,正方形被很好地绘制到屏幕上,但是运动事件什么也没做。
我关注了运动事件,虽然它们被提供给"new"渲染器,但它似乎将运动事件提供给旧屏幕。或者更确切地说是屏幕上的旧对象。这与我在 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(我制作的一个对象......),它被注册为一个监听器(我所说的监听器是我自己的实现......)运动事件。我已经为这些创建了自己的事件系统:
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);
监听器接口(interface):
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?
这是怎么回事?我显然遗漏了一些明显的东西。就像不知何故,由于某种原因,听众列表是静态的,并且尽管应用程序被完全重制也没有被取消引用?
最佳答案
我怀疑您面临的问题可能与以下事实有关:原始运动事件在 onMotionEvent()
返回后被框架回收(返回到它们的池中)。
从您使用 InputObjects 的方式来看,我认为您可能会在其中保留对原始运动事件的引用,而不是复制事件数据。
无论您现在在何处使用 event
,都可以快速尝试使用 MotionEvent.obtain(event)
(这会创建一个副本),看看这是否会使奇怪的行为消失。当然,如果这可行,您最终将不得不在完成这些副本后回收()它们。不要在原始运动事件上调用 recycle()
。
干杯,Aert。
关于Android Activity 生命周期 - 重新启动(销毁)应用程序不会删除对(自定义)监听器的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5956790/