android - onPause/onResume 后无法绘制

标签 android

我正在编写我的第一个安卓游戏。它几乎在每个方面都运行良好,但是当屏幕超时开始并且我按下按钮返回游戏时,我发现游戏状态的图像卡住了。看起来主线程仍然存在 - 我可以这么说是因为当我在屏幕上拖动某些对象时会发出一组声音,并且声音仍然表现得好像一切正​​常(除了我除了卡住屏幕)。如果我然后选择一个菜单来显示“高分” Activity ,然后退出回到游戏,我发现一切都很好并且可以继续所有图形正常工作。

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

编辑:在 Brigham 的建议下,我对代码做了几个修改,但症状是一样的。

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

编辑: 有很多人对此问题没有解决方案 - 我认为这个问题一定非常棘手 - 或者可能没有在我发布的代码 fragment 中揭示。关于我如何诊断这个问题的一些建议将非常有用。

编辑:我现在将整个(简化的)项目放在 simple.zip 中,并将其放在网上:http://dl.dropbox.com/u/2969211/Simple.zip - 关键代码都在文件 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;
        }
    }
}

最佳答案

您的问题是您保留了 surf_holder,因为您的线程成员 witch 是错误的。当您的 Activity 进入休眠状态然后返回时,Surface Holder 正在发生变化,它也可能发生在屏幕旋转或其他 SurfaceView 事件上。因此,最佳做法是每次要绘制时从 View 中询问它。

@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 引用,不要将其保存在任何地方,删除您用于获取持有人的函数,也将其从您的线程中删除!。仅当您要锁定 Canvas 时才执行此操作:

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

关于android - onPause/onResume 后无法绘制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8821448/

相关文章:

android studio 3,如何配置sdk版本

java - firebaserecycleradapter 中的 firebaserecycleradapter() 不能应用于

android - 使用 Android 的 MediaPlayer 类播放资源视频

java - Android 正在记住我的旧包名称吗?

java - 如何安装必要的库以在 Android Studio 中使用 MultipartEntity?

android - TextInputLayout 和 AutoCompleteTextView

android - ImageView 与 Canvas

android - 连续语音识别意外停止

android - SQLITE - 根据位查询整数字段

Android - 如何在 FirebaseMessagingService 类中使用 Realm(非 Activity )