简体   繁体   中英

SurfaceView destroying Surface after a while of running

I'm trying to create a surfaceView that runs a gameloop thread, I've spent forever trying to solve this issue that I get after a little while of running, the game loop seems fine it continues to run and continues to throw the error after the first time, I've gotten many different errors and tried to track everything its doing so far what I'm getting is my canvas keeps returning null, it runs fine for a while and draws like its suppose to, but then returns null, I've put System.out.println(); in multiple spots to see if certain methods are running, and how many times they are (yes I know about using logs but I don't really like them), anyway what I've noticed is when I run the app, it runs the onResume, the onPause, then onResume again, then surfacedestroyed in the SurfaceView, the app continues to draw actually but keeps throwing the NPE to the canvas. I'm not sure, but I don't think the surfacedestroyed should be called while its running when I'm not doing anything. Here is my code for all the classes including Main:

package com.kojense.maverick.projectishgard.game;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Window;
import android.view.WindowManager;

public class Main extends AppCompatActivity {

    public static int COUNT = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(new GamePannel(this));
    }

    @Override
    public void onPause(){
        super.onPause();
        System.out.println("Paused");
    }

    @Override
    public void onResume(){
        super.onResume();
        System.out.println("Resumed");
    }

    @Override
    public void onStop(){
        super.onStop();
        System.out.println("Stopped");
    }
}

GamePannel:

package com.kojense.maverick.projectishgard.game;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.kojense.maverick.projectishgard.R;

/**
 * Created by Maverick on 5/2/2017.
 */

public class GamePannel extends SurfaceView implements SurfaceHolder.Callback {

    private GameThread thread;

    public static int WIDTH, HEIGHT, SPEED = 15;

    private HUD hud;
    private block b;

    public GamePannel(Context context){
        super(context);
        getHolder().addCallback(this);
        thread = new GameThread(getHolder(), this);
        setFocusable(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {

        this.WIDTH = getWidth();
        this.HEIGHT = getHeight();

        hud = new HUD(BitmapFactory.decodeResource(getResources(), R.drawable.b1));
        b = new block();

        thread.setRunning(true);
        thread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

        System.out.println("Destroyed");

    }

    @Override
    public boolean onTouchEvent(MotionEvent e){


        return super.onTouchEvent(e);
    }

    public void update(){

        b.update();

    }
    @Override
    public void draw(Canvas canvas){
        super.draw(canvas);

        canvas.drawColor(Color.WHITE);
        b.draw(canvas);

        hud.draw(canvas); //Keep at end to stay ontop
    }
}

GameThread:

package com.kojense.maverick.projectishgard.game;

import android.graphics.Canvas;
import android.view.SurfaceHolder;

/**
 * Created by Maverick on 5/2/2017.
 */

public class GameThread extends Thread implements Runnable {

    public static final int MAX_FPS = 30;
    private SurfaceHolder holder;
    private GamePannel pannel;
    private boolean running = true;
    private Canvas canvas;

    public GameThread(SurfaceHolder holder, GamePannel pannel){
        super();
        this.holder = holder;
        this.pannel = pannel;
    }

    public void setRunning(boolean r){ this.running = r;}

    @Override
    public void run(){

        long startTime, waitTime, totalTime = 1000/MAX_FPS;

        while(running){
            startTime = System.currentTimeMillis();
            canvas = null;

            try {
                canvas = this.holder.lockCanvas();
                synchronized (holder) {
                    this.pannel.update();
                    this.pannel.draw(canvas);
                }
            }catch (Exception e){
                e.printStackTrace();
            } finally{
                if(canvas != null) {
                    try {
                        holder.unlockCanvasAndPost(canvas);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }

            waitTime = totalTime-(System.currentTimeMillis() - startTime);

            try{
                if(waitTime > 0) {
                    sleep(waitTime);
                } else {
                    sleep(10);
                }
            }catch (Exception e){}
        }
    }
}

Error Log:

05-04 17:05:59.030 3993-4428/com.kojense.maverick.projectishgard D/mali_winsys: new_window_surface returns 0x3000,  [2560x1440]-format:1
05-04 17:05:59.070 3993-3993/com.kojense.maverick.projectishgard D/ViewRootImpl: MSG_RESIZED_REPORT: ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=2
05-04 17:05:59.080 3993-3993/com.kojense.maverick.projectishgard I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@22f318b time:7154875
05-04 17:05:59.080 3993-3993/com.kojense.maverick.projectishgard I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@9eb69c6 time:7154875
05-04 17:05:59.080 3993-3993/com.kojense.maverick.projectishgard V/ActivityThread: updateVisibility : ActivityRecord{b5a4703 token=android.os.BinderProxy@9eb69c6 {com.kojense.maverick.projectishgard/com.kojense.maverick.projectishgard.splash.SplashScreen}} show : false
05-04 17:06:06.890 3993-3993/com.kojense.maverick.projectishgard I/Timeline: Timeline: Activity_launch_request id:com.kojense.maverick.projectishgard time:7162687
05-04 17:06:06.910 3993-3993/com.kojense.maverick.projectishgard I/System.out: Paused
05-04 17:06:06.920 3993-3993/com.kojense.maverick.projectishgard W/ResourcesManager: getTopLevelResources: /data/app/com.kojense.maverick.projectishgard-1/base.apk / 1.0 running in com.kojense.maverick.projectishgard rsrc of package com.kojense.maverick.projectishgard
05-04 17:06:06.930 3993-3993/com.kojense.maverick.projectishgard D/Activity: performCreate Call Injection manager
05-04 17:06:06.930 3993-3993/com.kojense.maverick.projectishgard I/InjectionManager: dispatchOnViewCreated > Target : com.kojense.maverick.projectishgard.game.Main isFragment :false
05-04 17:06:06.930 3993-3993/com.kojense.maverick.projectishgard I/System.out: Resumed
05-04 17:06:06.930 3993-3993/com.kojense.maverick.projectishgard D/SecWifiDisplayUtil: Metadata value : SecSettings2
05-04 17:06:06.930 3993-3993/com.kojense.maverick.projectishgard D/ViewRootImpl: #1 mView = com.android.internal.policy.PhoneWindow$DecorView{8d8c1d6 I.E...... R.....ID 0,0-0,0}
05-04 17:06:06.950 3993-4428/com.kojense.maverick.projectishgard D/mali_winsys: new_window_surface returns 0x3000,  [2560x1440]-format:1
05-04 17:06:07.000 3993-3993/com.kojense.maverick.projectishgard D/ViewRootImpl: MSG_RESIZED_REPORT: ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=2
05-04 17:06:07.020 3993-3993/com.kojense.maverick.projectishgard I/System.out: Destroyed
05-04 17:06:07.030 3993-3993/com.kojense.maverick.projectishgard I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@b9191f1 time:7162823
05-04 17:06:07.100 3993-4456/com.kojense.maverick.projectishgard W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int, android.graphics.PorterDuff$Mode)' on a null object reference
05-04 17:06:07.100 3993-4456/com.kojense.maverick.projectishgard W/System.err:     at android.view.SurfaceView.dispatchDraw(SurfaceView.java:451)
05-04 17:06:07.100 3993-4456/com.kojense.maverick.projectishgard W/System.err:     at android.view.View.draw(View.java:17479)
05-04 17:06:07.100 3993-4456/com.kojense.maverick.projectishgard W/System.err:     at android.view.SurfaceView.draw(SurfaceView.java:442)
05-04 17:06:07.100 3993-4456/com.kojense.maverick.projectishgard W/System.err:     at com.kojense.maverick.projectishgard.game.GamePannel.draw(GamePannel.java:72)
05-04 17:06:07.100 3993-4456/com.kojense.maverick.projectishgard W/System.err:     at com.kojense.maverick.projectishgard.game.GameThread.run(GameThread.java:39)
05-04 17:06:07.270 3993-3993/com.kojense.maverick.projectishgard I/System.out: Stopped
05-04 17:06:07.270 3993-3993/com.kojense.maverick.projectishgard V/ActivityThread: updateVisibility : ActivityRecord{eca5344 token=android.os.BinderProxy@22f318b {com.kojense.maverick.projectishgard/com.kojense.maverick.projectishgard.game.Main}} show : false

Edit:

I found the Error I believe, Samsung devices pause apps and resume them, I tried this code on my friends phone and he didn't have the pausing errors, then I tried it on another Samsung device running the newest version of android and same issue (the current one I'm testing on is Running M). I'm guessing when it does that it destroys the surfaceview and causes the canvas become null. So I guess I just need to figure out how to pause and resume a thread if anyone wants to help me out with that, also does anyone know if when the phones does that and destroys the surfaceview (runs method surfacedestroyed) that if I need to reCreate the surface or just continue with the thread (resume thread). Thanks Guys BTW!

Add this line of code in surfaceDestroyed method.

@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

       boolean retry= true;
       thread.setRunning(false);
       while(retry){
         try{
              thread.join();
              retry=false;

            }catch(InterruptedException e){
               Log.e("GamePannel","Exception in surfaceDestroyed",e);
            }
      }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM