安卓; “密钥调度超时...”

发布于 2024-10-03 12:29:13 字数 12710 浏览 4 评论 0原文

我有一个菜单活动和一个从菜单启动的游戏活动。 有些(大多数)时间我启动游戏活动;所有输入都会挂起几秒(最多 10 秒左右),然后以超高速播放,而我在 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;
}

}

可能是什么原因造成的?欢迎任何想法/猜测。是的,我知道这是一堵相当大的代码墙需要筛选。

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}}}

The menu activity:

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;

}

The game activity:

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦行七里 2024-10-10 12:29:13

“按键调度超时”的一个常见原因是在调试器中占用 UI 线程(处理 UI 事件)的时间超过很短的时间(详细信息如下),这是我经常遇到的情况,直到深入挖掘。 。例如,如果您想调试事件处理程序中的代码,这就是潜在的问题。

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

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

...并且您保留该线程 (UI):

5 秒后您将收到此警告:
发送到 com.hos/com.hos.MyActivity 的密钥调度超时
... Window 为 null ...

20 秒后您将得到:
发送到 com.hos/com.hos.MyActivity 的密钥调度超时
... 窗口为空 ...
继续等待密钥发送

35 秒后您将得到:
发送到 com.hos/com.hos.MyActivity 的密钥调度超时
... 窗口为空 ...
超时过期进程下一个密钥&寻找新目标

此时,不仅应用程序被冻结,手机也被冻结。
我经常需要等待 ANR,有时还需要硬重启手机。

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

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

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

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 线程上同步或使用任何“等待”函数。或者,如果您需要,请确保速度很快。这是一个等待发生的竞争条件。特别是如果它不仅影响您的应用程序,还影响您的手机。

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

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

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.

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
    }
}

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

After 5 seconds you will get this warning:
Key dispatching timed out sending to com.hos/com.hos.MyActivity
... null to 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

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

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.

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

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

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(?);
        }
    }
}

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(?);
            }
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文