Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/216.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 暂停/恢复后无法绘制_Android - Fatal编程技术网

Android 暂停/恢复后无法绘制

Android 暂停/恢复后无法绘制,android,Android,我正在写我的第一个android游戏。它几乎在各个方面都工作得很好,但是当屏幕超时开始时,我按下按钮返回游戏,我发现游戏状态的图像冻结了。主线程似乎仍然处于活动状态-我可以告诉你这一点,因为当我在屏幕上拖动某些对象时,会出现一组声音,这些声音仍然表现得好像一切正常(除了除了冻结的屏幕之外,我什么也看不到)。如果我选择一个菜单来显示“high scores”活动,然后退出游戏,我发现一切都很好,可以继续所有图形正常工作 我不太确定诊断此问题需要包含代码的哪些部分,但我猜,如果需要,我将添加更多内容

我正在写我的第一个android游戏。它几乎在各个方面都工作得很好,但是当屏幕超时开始时,我按下按钮返回游戏,我发现游戏状态的图像冻结了。主线程似乎仍然处于活动状态-我可以告诉你这一点,因为当我在屏幕上拖动某些对象时,会出现一组声音,这些声音仍然表现得好像一切正常(除了除了冻结的屏幕之外,我什么也看不到)。如果我选择一个菜单来显示“high scores”活动,然后退出游戏,我发现一切都很好,可以继续所有图形正常工作

我不太确定诊断此问题需要包含代码的哪些部分,但我猜,如果需要,我将添加更多内容:

编辑:根据Brigham的建议,我对代码进行了一些修改,但症状相同

编辑:我注意到,如果我单击一个按钮发起“查看高分”活动,则会调用surfaceDestroyed()。但是当屏幕超时开始时,不会调用surfaceDestroyed()

编辑:对于这个问题,有很多观点都没有找到解决方案——我想这个问题一定很棘手——或者可能没有在我发布的代码片段中透露出来。关于如何诊断此问题的一些建议将非常有用

编辑:我现在已将整个(简化的)项目放在simple.zip中,并将其放到web上:-关键代码都在simple.java文件中

    MicksPanelThing mpt = null;
    public MicksThreadThing micks_thread_thing = null;

    @Override
    protected void onPause() // pair with onResume
    {
        super.onPause();
        allow_draw.set(false);
        micks_thread_thing.setRunning(false);
        save_state();
    }


    @Override
    protected void onResume() // pair with onPause
    {
        super.onResume();
        get_state();
        mpt.get_a_new_thread_all_over_again();
        micks_thread_thing.setRunning(true);
        allow_draw.set(true);
    }

////////////////////////////////////////////////////////////////////////////

    public class MicksPanelThing extends SurfaceView implements SurfaceHolder.Callback
    {
        public MicksPanelThing(Context context) 
        {
            super(context);
        }

        public void get_a_new_thread_all_over_again()
        {
            getHolder().addCallback(this);
            micks_thread_thing = new MicksThreadThing(getHolder(), this);
            setFocusable(true);        
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) 
        {
            synchronized (micks_thread_thing.getSurfaceHolder()) 
            {
                if (event.getAction() == MotionEvent.ACTION_DOWN) 
                {
                    // blah
                }
                if (event.getAction() == MotionEvent.ACTION_MOVE && selected_node != -1) 
                {
                    // blah
                }
                if (event.getAction() == MotionEvent.ACTION_UP) 
                {
                     // blah
                }
                return true;
            }
        }

        @Override
        public void onDraw(Canvas canvas) 
        {
            canvas_width = canvas.getWidth();
            canvas_height = canvas.getHeight();

            if (allow_draw.get())
            {   
                canvas.drawBitmap(sandy_bitmap, 0, 0, null);                

                // blah
            }

        }

        public void surfaceCreated(SurfaceHolder holder) 
        {
            micks_thread_thing.setRunning(true);
            micks_thread_thing.start();
            we_have_a_surface = true;
        }

        public void surfaceDestroyed(SurfaceHolder holder) 
        {
            boolean retry = true;
            micks_thread_thing.setRunning(false);
            while (retry) 
            {
                try 
                {
                    micks_thread_thing.join();
                    retry = false;
                    micks_thread_thing = null;
                } 
                catch (InterruptedException e) 
                {
                    // we will try it again and again...
                }
            }
            we_have_a_surface = false;
        }
    }

    class MicksThreadThing extends Thread 
    {
        private SurfaceHolder surf_holder = null;
        private MicksPanelThing micks_panel_thing;
        private boolean this_thread_is_currently_active = false;

        public MicksThreadThing(SurfaceHolder surfaceHolder, MicksPanelThing mpt) 
        {
            surf_holder = surfaceHolder;
            micks_panel_thing = mpt;
        }

        public void setRunning(boolean set_run) 
        {
            this_thread_is_currently_active = set_run;
        }

        public SurfaceHolder getSurfaceHolder() 
        {
            return surf_holder;
        }

        @Override
        public void run() 
        {
            Canvas c;
            while (this_thread_is_currently_active) 
            {
                c = null;
                try 
                {
                    c = surf_holder.lockCanvas(null);
                    synchronized (surf_holder) 
                    {
                        micks_panel_thing.onDraw(c);
                    }
                } 
                finally 
                {
                    if (c != null) 
                    {
                        surf_holder.unlockCanvasAndPost(c);
                    }
                }
            }
        }
    }

public class Allow_draw
{
    private boolean draw;

    Allow_draw()
    {
        draw = false;
    }
    public void set(boolean x)
    {
        synchronized (this)
        {
            draw = x;
        }
    }
    boolean get()
    {
        synchronized (this)
        {
            return draw;
        }
    }
}

onPause
中调用
setRunning(false)
后,您的
MicksThreadThing
实例正在死亡,因为
while
循环条件变为false,并且
run
方法退出


您应该在
onResume
中创建一个新的
MicksThreadThing
,或者使用某种同步来暂停run方法,直到用户恢复游戏。我建议使用
CountDownLatch
类来完成此任务。它将允许您的
run
方法调用
countDownLatch.await()
,此时线程将暂停,直到您在
onResume
方法中调用
countDownLatch.countDown()

此外,
this\u thread\u当前处于活动状态
变量应设置为
volatile

private volatile boolean this_thread_is_currently_active = false;

onPause
中调用
setRunning(false)
后,您的
MicksThreadThing
实例正在死亡,因为
while
循环条件变为false,并且
run
方法退出


您应该在
onResume
中创建一个新的
MicksThreadThing
,或者使用某种同步来暂停run方法,直到用户恢复游戏。我建议使用
CountDownLatch
类来完成此任务。它将允许您的
run
方法调用
countDownLatch.await()
,此时线程将暂停,直到您在
onResume
方法中调用
countDownLatch.countDown()

此外,
this\u thread\u当前处于活动状态
变量应设置为
volatile

private volatile boolean this_thread_is_currently_active = false;

你的问题是你的
surf_持有者
,因为你的线程成员是错误的。当您的活动进入睡眠状态,然后返回时,surface holder正在更改,也可能发生在屏幕旋转或其他SurfaceView事件上。因此,最好的做法是,每次你要画画的时候,都从视图中询问它

@Override
        public void run() 
        {
            Canvas c;
            while (this_thread_is_currently_active) 
            {
                c = null;
                try 
                {
                    Final SurfaceHolder holder = getHolder();
                    c = holder.lockCanvas(null);
                    if(c != null)// may happen when SurfaceHolder is changing
                        synchronized (surf_holder) 
                        {
                            micks_panel_thing.onDraw(c);
                        }
                    }
                } 
                finally 
                {
                    if (c != null) 
                    {
                        surf_holder.unlockCanvasAndPost(c);
                    }
                }
            }
        }

不,不,不!你做错了

删除您从SurfaceHolder获得的所有引用,不要将其保存在任何位置,删除您用于获取保持架的函数,也将其从线程中删除!。只有当您要锁定画布时,才能执行以下操作:

//inside surfaceView
    public void updateView(){
        final SurfaceHolder holder = getHolder();

        try{
        Canvas canvas = holder.lockCanvas();
        if(canvas != null){
            onDraw(canvas);
        }
        holder.unlockCanvasAndPost(canvas);
        }
        catch (Exception e) {
            // TODO: handle exception
        }
    }

你的问题是你的
surf_持有者
,因为你的线程成员是错误的。当您的活动进入睡眠状态,然后返回时,surface holder正在更改,也可能发生在屏幕旋转或其他SurfaceView事件上。因此,最好的做法是,每次你要画画的时候,都从视图中询问它

@Override
        public void run() 
        {
            Canvas c;
            while (this_thread_is_currently_active) 
            {
                c = null;
                try 
                {
                    Final SurfaceHolder holder = getHolder();
                    c = holder.lockCanvas(null);
                    if(c != null)// may happen when SurfaceHolder is changing
                        synchronized (surf_holder) 
                        {
                            micks_panel_thing.onDraw(c);
                        }
                    }
                } 
                finally 
                {
                    if (c != null) 
                    {
                        surf_holder.unlockCanvasAndPost(c);
                    }
                }
            }
        }

不,不,不!你做错了

删除您从SurfaceHolder获得的所有引用,不要将其保存在任何位置,删除您用于获取保持架的函数,也将其从线程中删除!。只有当您要锁定画布时,才能执行以下操作:

//inside surfaceView
    public void updateView(){
        final SurfaceHolder holder = getHolder();

        try{
        Canvas canvas = holder.lockCanvas();
        if(canvas != null){
            onDraw(canvas);
        }
        holder.unlockCanvasAndPost(canvas);
        }
        catch (Exception e) {
            // TODO: handle exception
        }
    }
试试这个: 在曲面销毁方法中添加以下内容:

支架.解锁CanvasandPost(主线.画布)

编辑:

试试这个: 在曲面销毁方法中添加以下内容:

支架.解锁CanvasandPost(主线.画布)

编辑:


“您应该在onResume中创建一个新的MicksThreadThing”-但我认为这是我已经在做的:if(micks_thread_thing==null){mpt.get_a_new_thread_all_over_()}只有在某个点设置为null时才会发生这种情况。在哪里设置为空?我现在看到了。确保调用了
surfaceDestroyed
,并在onResume中添加一条log语句,以确保
micks\u thread\u thing
为空。执行setRunning(false)后,micks\u thread\u thing对象是否仍然存在(尽管未运行)-即,我需要重新运行它还是需要创建一个新的?它仍然存在,但一旦运行方法退出,线程对象就不能再次启动。您必须创建一个新的线程。“您应该在onResume中创建一个新的MicksThreadThing”-但我认为这是我已经在做的:if(micks_thread_thing==null){mpt.get_a_new_thread_all_over_()}只有在某个点设置为null时才会发生这种情况。在哪里设置为空?我现在看到了。确保调用了
surfaceDestroyed
,并在onResume中添加一条log语句,以确保
micks\u thread\u thing
为null。setRun之后