安卓; “密钥调度超时..." [英] Android; "Key dispatching timed out ..."

查看:128
本文介绍了安卓; “密钥调度超时..."的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个菜单活动和一个从菜单启动的游戏活动. 在我发起游戏活动的某些(大部分)时间中;所有输入都挂起几秒钟(最多10秒钟),然后以超高速播放,而我在logcat中得到提示:

I've got a menu activity and a game activity which is launched from the menu. Some (most) of the times I launch the game activity; all input hangs for a few (up to 10-ish) seconds and then plays out in hyperspeed while i get this in logcat:

11-20 18:24:27.873: WARN/WindowManager(2473): Key dispatching timed out sending to southgrove.game/southgrove.game.Game
11-20 18:24:27.873: WARN/WindowManager(2473): Previous dispatch state: {{KeyEvent{action=1 code=4 repeat=0 meta=0 scancode=28 mFlags=8} to Window{4866c7a0 southgrove.game/southgrove.game.Game paused=false} @ 1290273811209 lw=Window{4866c7a0 southgrove.game/southgrove.game.Game paused=false} lb=android.os.BinderProxy@484e8a58 fin=false gfw=true ed=true tts=0 wf=false fp=false mcf=Window{4866c7a0 southgrove.game/southgrove.game.Game paused=false}}}
11-20 18:24:27.873: WARN/WindowManager(2473): Current dispatch state: {{null to Window{4833d500 southgrove.game/southgrove.game.Game paused=false} @ 1290273867876 lw=Window{4833d500 southgrove.game/southgrove.game.Game paused=false} lb=android.os.BinderProxy@485487b0 fin=false gfw=true ed=true tts=0 wf=false fp=false mcf=Window{4833d500 southgrove.game/southgrove.game.Game paused=false}}}

菜单活动:

package southgrove.game;

import southgrove.game.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;

public class Menu extends Activity
{

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);

    setContentView(R.layout.menu);

    View playButton = findViewById(R.id.play);
    playButton.setOnClickListener(new OnClickListener()
    {
        public void onClick(View view)
        {
            startActivityForResult(new Intent(Menu.this, Game.class), 0);
        }
    });

    View testButton = findViewById(R.id.test);
    testButton.setOnClickListener(new OnClickListener()
    {
        public void onClick(View view)
        {
            startActivityForResult(new Intent(Menu.this, Test.class), 0);
        }
    });

    View closeButton = findViewById(R.id.close);
    closeButton.setOnClickListener(new OnClickListener()
    {
        public void onClick(View view)
        {
            showDialog(QUIT_DIALOG);
        }
    });

}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
    if (keyCode == KeyEvent.KEYCODE_BACK)
    {
        showDialog(QUIT_DIALOG);
    }

    return super.onKeyDown(keyCode, event);
}

@Override
protected Dialog onCreateDialog(int id)
{
    Dialog dialog;

    switch (id)
    {
        case QUIT_DIALOG:
            AlertDialog.Builder quitDialogBuilder = new AlertDialog.Builder(this);
            quitDialogBuilder.setMessage("Exit the game?")
                    .setCancelable(false)
                    .setPositiveButton("Yes", new DialogInterface.OnClickListener()
                    {
                        public void onClick(DialogInterface dialog, int id)
                        {
                            Menu.this.finish();
                        }
                    })
                    .setNegativeButton("No", new DialogInterface.OnClickListener()
                    {
                        public void onClick(DialogInterface dialog, int id)
                        {
                            dialog.cancel();
                        }
                    });
            dialog = quitDialogBuilder.create();
        break;

        default:
            dialog = null;
    }

    return dialog;
}

private final int   QUIT_DIALOG = 0;

}

游戏活动:

package southgrove.game;

import southgrove.droidgl.DroidGL;
import southgrove.droidgl.core.Camera;
import southgrove.droidgl.core.Node;
import southgrove.droidgl.core.RootNode;
import southgrove.game.R;
import southgrove.game.board.BoardBase;
import southgrove.game.board.core.*;
import southgrove.game.cameras.StupidCamera;
import southgrove.input.OnTouchFilter;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.widget.TextView;

public class Game extends Activity
{

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);

    setContentView(R.layout.game);

    // Get fpsTextView reference
    fpsTextView = (TextView) findViewById(R.id.fpsTextView);

    // Build meshes
    TetrominoMesh.buildMeshes();

    // Setup the DroidGL surface
    droidgl = (DroidGL) findViewById(R.id.droidGL);
    droidgl.setLongClickable(true);
    droidgl.setOnTouchListener(new GameSurfaceOnTouchFilter(false));

    // Create and add camera
    final Camera camera = new StupidCamera();
    camera.move(0, 0, 14);
    droidgl.registerCamera(camera);
    DroidGL.setActiveCamera(camera);

    // Create and add root node
    final Node rootNode = new RootNode();
    droidgl.setRootNode(rootNode);

    // Create and add game board
    gameBoard = new GameBoard(droidgl, 32, 32, 8);
    rootNode.addChild(gameBoard);

    // start up updateHandler
    updateHandler = new UpdateHandler();
    updateHandler.sleep(1);

    // get vibrator service
    vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
}

@Override
public void onBackPressed()
{
    showDialog(QUIT_DIALOG);
}

@Override
protected Dialog onCreateDialog(int id)
{
    Dialog dialog;

    switch (id)
    {
        case QUIT_DIALOG:
            AlertDialog.Builder quitDialogBuilder = new AlertDialog.Builder(this);
            quitDialogBuilder.setMessage("Really quit?")
                    .setCancelable(false)
                    .setPositiveButton("Yup!", new DialogInterface.OnClickListener()
                    {
                        public void onClick(DialogInterface dialog, int id)
                        {
                            Game.this.finish();
                        }
                    })
                    .setNegativeButton("Nope!", new DialogInterface.OnClickListener()
                    {
                        public void onClick(DialogInterface dialog, int id)
                        {
                            dialog.cancel();
                        }
                    });
            dialog = quitDialogBuilder.create();
        break;

        default:
            dialog = null;
    }

    return dialog;
}

@Override
protected void onPause()
{
    super.onPause();
    droidgl.onPause();
}

protected void onUpdate()
{
    fpsTextView.setText("fps: " + String.valueOf(droidgl.getFps()));
    updateHandler.sleep(500);
}

@Override
protected void onResume()
{
    super.onResume();
    droidgl.onResume();
}

private DroidGL         droidgl;
private GameBoard       gameBoard;
private TextView        fpsTextView;
private Vibrator        vibrator;

private UpdateHandler   updateHandler;

private final int       QUIT_DIALOG = 0;

private class UpdateHandler extends Handler
{
    @Override
    public void handleMessage(Message msg)
    {
        Game.this.onUpdate();
    }

    public void sleep(long delayMillis)
    {
        this.removeMessages(0);
        if (!Game.this.isFinishing())
            sendMessageDelayed(obtainMessage(0), delayMillis);
    }
}

private class GameSurfaceOnTouchFilter extends OnTouchFilter
{
    public GameSurfaceOnTouchFilter(Boolean consumeEvent)
    {
        super(consumeEvent);
    }

    private float   flipDeltaX;
    private float   flipDeltaY;

    protected void doubleTap(float x, float y)
    {
        super.doubleTap(x, y);

        synchronized (gameBoard)
        {
            if (gameBoard.dropCursorTetromino())
            {
                gameBoard.resetReactorTimer();
                gameBoard.setCursorTetromino((int) (Tetromino.NUM_TYPES * Math.random() - 1), 0);
                if (gameBoard.removeConnectedTetrominoes(3))
                {
                    gameBoard.startShockWave(0, 0, 10f, 0.35f);
                    vibrator.vibrate(300);
                } else
                {
                    vibrator.vibrate(50);
                }
            }
        }
    }

    protected void down(int pointer, float x, float y)
    {
        super.down(pointer, x, y);

        if (pointer == 0)
        {
        }

        if (pointer == 1)
        {
            flipDeltaX = 0;
            flipDeltaY = 0;
        }
    }

    protected void up(int pointer, float x, float y)
    {
        super.up(pointer, x, y);

        synchronized (gameBoard)
        {
        }
    }

    protected void move(int pointer, float x, float y, float dx, float dy)
    {
        super.move(pointer, x, y, dx, dy);

        synchronized (gameBoard)
        {
            if (pointer == 0)
            {
                gameBoard.addInertia(-dx * 0.0045f, dy * 0.0045f);
            }

            if (pointer == 1)
            {
                flipDeltaX -= dx;
                flipDeltaY += dy;

                if (Math.abs(flipDeltaX) > 45 || Math.abs(flipDeltaY) > 45)
                {
                    vibrator.vibrate(50);

                    if (Math.abs(flipDeltaX) > Math.abs(flipDeltaY))
                    {
                        if (flipDeltaX > 0)
                        {
                            gameBoard.rotateCursorTetromino(1);
                        } else
                        {
                            gameBoard.rotateCursorTetromino(-1);
                        }
                    } else
                    {
                        if (flipDeltaY > 0)
                        {
                            gameBoard.rotateCursorTetromino(1);
                        } else
                        {
                            gameBoard.rotateCursorTetromino(-1);
                        }
                    }
                    flipDeltaX = 0;
                    flipDeltaY = 0;
                }
            }
        }
    }

}

private class GameBoard extends BoardBase
{

    public GameBoard(DroidGL droidGL, int width, int height, int depth)
    {
        super(droidGL, width, height, depth);
    }

    public void resetReactorTimer()
    {
        synchronized (this)
        {
            reactorTimer = 0;
        }
    }

    public void startShockWave(int gridPosX, int gridPosY, float length, float magnitude)
    {
        synchronized (this)
        {
            for (int i = 0; i < tetrominoes.size(); i++)
            {
                tetrominoes.get(i).bounce(
                        (float) (Math.random() * 0.12f),
                        (float) (Math.random() * magnitude)
                        );
            }
        }
    }

    @Override
    protected void onSetup()
    {
        synchronized (this)
        {
            setCursorTetromino((int) (Tetromino.NUM_TYPES * Math.random()), 0);

            for (int i = 0; i < 1024; i++)
            {
                addTetromino(
                        (int) (Math.random() * Tetromino.NUM_TYPES),
                        (int) (Math.random() * width / 2) * 2,
                        (int) (Math.random() * height / 2) * 2,
                        (int) (Math.random() * 2),
                        (int) (Math.random() * 4));
            }

            removeConnectedTetrominoes(3);
        }
    }

    @Override
    protected void onLogic(float timeFactor)
    {
        synchronized (this)
        {
            if (shiftTimer > shiftTime || tetrominoes.size() < 15)
            {
                shiftTimer = 0;
                shiftTime -= shiftTime / 5;

                shiftUp();

                for (int i = 0; i < 256; i++)
                {
                    addTetromino(
                            (int) (Math.random() * Tetromino.NUM_TYPES),
                            (int) (Math.random() * width / 2) * 2,
                            (int) (Math.random() * height / 2) * 2,
                            0,// (int) (Math.random() * (depth - 1)),
                            (int) (Math.random() * 4));
                }
            }

            if (reactorTimer > 1f)
            {
                reactorTimer = 0;

                drop();
                removeConnectedTetrominoes(3);
            }

            reactorTimer += timeFactor;
            shiftTimer += timeFactor;
        }
    }

    private float   shiftTime   = 60 * 5;
    private float   reactorTimer;
    private float   shiftTimer;
}

}

可能是什么原因造成的?任何想法/推测都是值得欢迎的.是的,我知道那是一堵相当大的代码墙.

What could be causing this? Any ideas/speculations are welcome. And yes, I know that's a pretty massive wall of code to sift through.

推荐答案

密钥分配超时"的一个常见原因是我坚持使用UI线程-该UI处理UI,直到深入研究为止.事件-在调试器中持续的时间不超过一小段时间(详细信息如下).例如,如果您想在事件处理程序中调试代码,则可能是潜在的问题.

One common cause of the "Key dispatching timed out", which I experienced quite often until digging a little deeper, is holding onto the UI thread - which handles UI events - in the debugger for more than a short amount of time (details below). For instance, if you want to debug code in your event handler, this is potential problem.

例如,如果您在Activity的onTouchEvent()中设置了断点

For example, if you set a breakpoint in onTouchEvent() of an Activity

class MyActivity extends Activity
{
    public boolean onTouchEvent(MotionEvent me)
    {
        // ** Breakpoint ** 
        // Code you wish to debug
    }
}

...,然后继续使用此线程(UI):

... and you hold on to this thread (UI):

5秒后,您将收到以下警告: 密钥分发超时发送到com.hos/com.hos.MyActivity ...对Window无效...

After 5 seconds you will get this warning: Key dispatching timed out sending to com.hos/com.hos.MyActivity ... null to Window ...

20秒后,您将获得: 密钥分发超时发送到com.hos/com.hos.MyActivity ...对Window无效... 继续等待密钥被分发

After 20 seconds you will get: Key dispatching timed out sending to com.hos/com.hos.MyActivity ... null to Window ... Continuing to wait for key to be dispatched

35秒后,您将获得: 密钥分发超时发送到com.hos/com.hos.MyActivity ...对Window无效... 下一个键&超时的进程超时找到新的目标

After 35 seconds you will get: Key dispatching timed out sending to com.hos/com.hos.MyActivity ... null to Window ... timed out expired process next Key & find new target

这时,不仅应用程序被冻结,电话也被冻结. 我经常需要等待ANR,有时需要硬重启手机.

At this point, not only is the application frozen but so is the phone. Quite often I need to wait for the ANR and sometimes hard restart the phone.

因此,一个简单的答案就是不要坚持使用UI线程,无论是使用调试器还是使用耗时的代码.

So one simple answer is don't hold on to the UI thread, whether it be with the debugger or with time-expensive code.

=============

=============

关于同步,这是一个非常相似的问题.在此示例中,onTouchEvent()可能必须等待非线程安全共享资源的填充.在这种情况下,如果触摸事件期间发生填充,则可能会超时.

Regarding synchronization, this is a very similar problem. In this example, an onTouchEvent() may have to wait for the population of a non-thread-safe shared resource. In which case it may timeout if population is occurring during the touch event.

class MyActivity extends Activity
{
    private static ArrayList<Object> m_alShared = new ArrayList<Object>();

    public boolean onTouchEvent(MotionEvent me)
    {
        synchronized(this)
        {
            // accessed shared resource.
            m_alShared.get(?);
        }
    }

    public void methodCalledByBackgroundThread()
    {
        synchronized(this)
        {
            // populate shared resource for more than 35 seconds
            while (/* time < 35 seconds */)
                m_alShared.add(?);
        }
    }
}

我个人选择不同步或在UI线程上使用任何等待"功能.或者,如果需要,请确保它很快.这是一个等待发生的比赛条件.特别是如果它不仅影响您的应用程序,还影响您的手机.

Personally, I choose to not synchronize or use any "wait" function on the UI thread. Or if you need to, make sure it's quick. It's a race condition waiting to happen. Especially if it affects not only your app, but your phone.

即我可能会选择以下解决方案并同步每个添加.

i.e. I might opt for the following solution and synchronize each add.

    public void methodCalledByBackgroundThread()
    {
        while (/* time < 35 seconds */)
        {
            synchronized(this)
            {
                // populate shared resource for more than 35 seconds
                m_alShared.add(?);
            }
        }
    }

这篇关于安卓; “密钥调度超时..."的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆