运行

时间:2017-05-04 22:09:11

标签: android multithreading canvas surfaceview surfaceholder

我试图创建一个运行游戏循环线程的surfaceView,我花了很长时间试图解决这个问题,这是我在运行一段时间后得到的,游戏循环看起来很好,它继续运行并且在第一次之后继续抛出错误,我得到了许多不同的错误并试图跟踪它到目前为止所做的一切我得到的是我的画布一直返回null,它运行良好一段时间像它假设的那样绘制,但是然后返回null,我已经把System.out.println();在多个位置查看某些方法是否正在运行,以及它们有多少次(是的我知道使用日志但我不是非常喜欢它们),无论如何,我注意到的是当我运行应用程序时,它运行onResume,onPause,然后再运行onResume,然后在SurfaceView中进行surfacedestroyed,应用程序继续实际绘制,但不断将NPE抛向画布。我不确定,但是当我没有做任何事情时,我不认为应该在它运行时调用表面破坏。这是我所有类的代码,包括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){}
        }
    }
}

错误日志:

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

编辑:

我发现错误我相信,三星设备暂停应用程序并恢复它们,我在我的朋友手机上尝试了这个代码并且他没有暂停错误,然后我在另一台运行最新版本的三星设备上尝试过android和同样的问题(目前正在测试的是运行M)。我猜测它何时会破坏surfaceview并导致画布变为null。所以我想我只需要弄明白如何暂停和恢复一个线程,如果有人想帮我解决这个问题,也有人知道当手机这样做并破坏surfaceview(运行方法surfacedestroyed),如果我需要重新创建曲面或继续线程(恢复线程)。谢谢大家BTW!

1 个答案:

答案 0 :(得分:0)

在surfaceDestroyed方法中添加这行代码。

@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);
            }
      }
}