-1

私は簡単なAndroidゲームを開発していますが、テスト中に問題に遭遇しています。 Lenovo Tab3 7タブレット(Android 5.0.1)またはLG P880電話(Android 4.0.3)で動作させるとうまく動作します。私はサムスンS7携帯電話(アンドロイド7.0)のゲームでそれを実行すると正常に動作します。私が意味することは、何も問題なく連続して10回実行できるということですが、ゲームが5〜30秒間停止するか、応答が停止することがあります。これは、通常、新しいアクティビティの開始時またはその直後に発生します。シンプルゲームはタブレットで動作しますが、時々電話に遅れます

ゲームレイアウトとしてSurfaceViewを長時間使用4 Activitiesを有しています。すべてのSurfaceViewsはRunnableを実装しています。アクティビティ:スプラッシュ画面(noHistory =マニフェストの「true」)、メニュー、難易度の選択とゲーム。

私はmdpi drawablesしか使用せず、すべての画面サイズに比例して調整します。ビットマップはBitmapFactory.decodeResourceを使用してロードされ、BitmapFactory.OptionsinDensity = 1,inScaled = falseとなります。

問題が発生すると、logcatはガベージコレクションのみを表示します。場合によっては、ゲームが5〜30秒間「一時停止」(タップが登録されていない)して正常に再開します。応答がないために再起動する必要があることがあります。私はゲームが何らかの理由で入力を収集しなくなったように感じます。入力はonTouchEventを無効にして、ACTION_UPがタップされた画像範囲内にあるかどうかをチェックすることによって処理されます。私が言ったように、これはタブレットやP880ではなく、S7(2台の電話機で試してみました)でしか起こらないので、Nougatまたは私には電話の下でdensityを強制することが考えられます。この原因と私はAndroidのゲーム開発に新しいもの

だから、私はアイデアを実行しているので、何をすることができ、誰もが/私は解決策を探してしなければならない任意のアイデアを持って知っているのですか? Nougat特有の設定/確認が必要ですか?強制的なピクセル密度はデバイスのパフォーマンスに何らかの影響を及ぼしますか?

編集1

globalApp

public class globalApp extends Application { 
SoundPool soundPool; 
SoundPool.Builder soundPoolBuilder; 

AudioAttributes audioAttributes; 
AudioAttributes.Builder audioAttributesBuilder; 

int soundTap, soundCorrect, soundIncorrect, soundVictory, soundDefeat; 
int soundBarrelVerySlow, soundBarrelSlow, soundBarrelNormal, soundBarrelFast, soundBarrelVeryFast; 

@Override 
public void onCreate() { 
    super.onCreate(); 

} 

public void buildSoundPool(){ 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
     audioAttributesBuilder = new AudioAttributes.Builder(); 
     audioAttributesBuilder.setUsage(AudioAttributes.USAGE_GAME); 
     audioAttributesBuilder.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION); 
     audioAttributes = audioAttributesBuilder.build(); 

     soundPoolBuilder = new SoundPool.Builder(); 
     soundPoolBuilder.setMaxStreams(2); 
     soundPoolBuilder.setAudioAttributes(audioAttributes); 
     soundPool = soundPoolBuilder.build(); 
    } 
    else { 
     soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0); 
    } 
} 

public void loadSounds(){ 
    soundBarrelVerySlow = soundPool.load(this,R.raw.very_slow_move, 1); 
    soundBarrelSlow = soundPool.load(this, R.raw.slow_move, 1); 
    soundBarrelNormal = soundPool.load(this, R.raw.slow_move, 1); 
    soundBarrelFast = soundPool.load(this,R.raw.fast_move, 1); 
    soundBarrelVeryFast = soundPool.load(this,R.raw.very_fast_move, 1); 
    soundTap = soundPool.load(this, R.raw.tap_sound, 1); 
    soundCorrect = soundPool.load(this, R.raw.correct, 1); 
    soundIncorrect = soundPool.load(this, R.raw.incorrect, 1); 
    soundVictory = soundPool.load(this, R.raw.victory, 1); 
    soundDefeat = soundPool.load(this, R.raw.defeat, 1); 
} 

public void playTap(){ 
    soundPool.play(soundTap, 1, 1,1, 0, 1); 
} 

public void playCorrect(){ 
    soundPool.play(soundCorrect, 1, 1,1, 0, 1); 
} 

public void playIncorrect(){ 
    soundPool.play(soundIncorrect, 1, 1,1, 0, 1); 
} 

public void playVictory(){ 
    soundPool.play(soundVictory, 1, 1,1, 0, 1); 
} 

public void playDefeat(){ 
    soundPool.play(soundDefeat, 1, 1,1, 0, 1); 
} 

public void playBarrelVerySlow(){soundPool.play(soundBarrelVerySlow, 1, 1, 1, 0, 1);} 

public void playBarrelSlow(){soundPool.play(soundBarrelSlow, 1, 1, 1, 0, 1);} 

public void playBarrelNormal(){ 
    soundPool.play(soundBarrelNormal, 1, 1,1, 0, 1); 
} 

public void playBarrelFast(){soundPool.play(soundBarrelFast, 1, 1, 1, 0, 1);} 

public void playBarrelVeryFast(){soundPool.play(soundBarrelVeryFast, 1, 1, 1, 0, 1);} 
} 

のMenuItem

public class MenuItem { 
private Bitmap bmp; 
private Context context; 

private Rect sourceRect; 
private RectF destRect; 

private int srcWidth; 
private int srcHeight; 

private int destW, destH; 

private int x, y; 
private int screenH; 

public MenuItem(Context ctx, String bmpName, int w, int x, int y, int sX, int sY){ 

    context = ctx; 

    BitmapFactory.Options bmpFOptions = new BitmapFactory.Options(); 
    bmpFOptions.inDensity = 1; 
    bmpFOptions.inScaled = false; 

    int res = context.getResources().getIdentifier(bmpName, "drawable", ctx.getPackageName()); 
    bmp = BitmapFactory.decodeResource(ctx.getResources(), res, bmpFOptions); 

    srcWidth = w; 
    srcHeight = bmp.getHeight(); 

    this.x = x; 
    this.y = y; 

    screenH = sY; 

    sourceRect = new Rect(0,0, srcWidth, srcHeight); 
    destRect = new RectF(); 

    setProportionalDestinationRect(sX, sY); 
} 

private void setProportionalDestinationRect(int scrX, int scrY) { 
    if (scrX != 1024 || scrY != 552){ 
     float propX = (float)scrX/1024; 
     float propY = (float)scrY/600; 
     // All drawables are designed for 1024x600 screen 
     // if device screen is different, scale image proportionally 

     destW = (int)(srcWidth * propX); 
     destH = (int) (srcHeight * propY); 
     x = (int) (x*propX); 
     y = (int) (y*propY); 
    } 
    else { 
     destW = srcWidth; 
     destH = srcHeight; 
    } 
    destRect.set(x,y, x+destW,y+destH); 
} 

public void update(){ 
} 

public Bitmap getBmp() { 
    return bmp; 
} 

public void setBmp(Bitmap bmp) { 
    this.bmp = bmp; 
} 

public Rect getSourceRect() { 
    return sourceRect; 
} 

public void setSourceRect(Rect sourceRect) { 
    this.sourceRect = sourceRect; 
} 

public RectF getDestRect() { 
    return destRect; 
} 

public void setDestRect(RectF destRect) { 
    this.destRect = destRect; 
} 

public boolean contains(int x, int y){ 
    if (destRect.left <= x && destRect.right >= x) 
     if (destRect.top <= y && destRect.bottom >= y) 
      return true; 
    return false; 
} 

public void setY(int y) { 
    this.y = y; 
    if (screenH != 552){ 
     float propY = (float)screenH/600; 
     y = (int) (y*propY); 
    } 
    destRect.set(x,y, x+destW,y+destH); 
} 
} 

MainActivity

public class MainActivity extends Activity { 
private boolean backPressedOnce = false; 
long backPressedTime = 0; 

private MainActivitySurface mainActivitySurface; 

globalApp app; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    //Setting full screen 
    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 

    View decorView = getWindow().getDecorView(); 
    int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 
    decorView.setSystemUiVisibility(uiOptions); 


    int x = getIntent().getIntExtra("screenWidth", 500); 
    int y = getIntent().getIntExtra("screenHeight", 500); 

    app = (globalApp) getApplication(); 
    app.buildSoundPool(); 
    app.loadSounds(); 

    mainActivitySurface = new MainActivitySurface(this, app, x, y); 
    mainActivitySurface.setParentActivity(MainActivity.this); 

    setContentView(mainActivitySurface); 
} 

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if (requestCode == 1001) { 
     if (resultCode == RESULT_OK) { 
      int result = data.getIntExtra("difficulty", 3); 
      mainActivitySurface.setResultDifficulty(result); 
     } 
    } 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
    mainActivitySurface.pause(); 
} 

@Override 
protected void onResume() { 
    super.onResume(); 
    backPressedOnce = false; 

    mainActivitySurface.resume(); 
} 

@Override 
public void onBackPressed() { 
     if (backPressedOnce && backPressedTime + 2000 > System.currentTimeMillis()) { 
      Process.killProcess(Process.myPid()); 
      System.exit(1); 
     } else { 
      Toast.makeText(this, "Press back again to exit.", Toast.LENGTH_SHORT).show(); 
      backPressedOnce = true; 
     } 
     backPressedTime = System.currentTimeMillis(); 
} 
} 

MainActivitySurface

public class MainActivitySurface extends SurfaceView implements Runnable { 

private Context context; 
private SurfaceHolder surfaceHolder; 
private Canvas canvas; 

private Thread thread = null; 

volatile private boolean running = false; 
private boolean surfaceCreated = false; 

private Intent playIntent; 
private Intent difficultyIntent; 

// Screen size 
private int screenWidth, screenHeight; 

//Menu items 
private MenuItem menuItemPlay, menuItemDifficulty, middleBarrel, bg; 
private int difficulty = 3; 

private Activity parentActivity; 
private globalApp app; 

public MainActivitySurface(Context ctx, globalApp a, int scrW, int scrH){ 
    super(ctx); 

    context = ctx; 
    screenHeight = scrH; 
    screenWidth = scrW; 

    app = a; 

    surfaceHolder = getHolder(); 

    surfaceHolder.addCallback(new SurfaceHolder.Callback() { 
     @Override 
     public void surfaceCreated(SurfaceHolder holder) { 
      surfaceCreated = true; 
     } 

     @Override 
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 

     } 

     @Override 
     public void surfaceDestroyed(SurfaceHolder holder) { 

     } 
    }); 

    bg = new MenuItem(context, "main_activity_background_single", 1024, 0, 0, scrW, scrH); 
    menuItemPlay = new MenuItem(context, "menu_item_play_single", 233,(1024-233)/2,100, scrW, scrH); 
    menuItemDifficulty = new MenuItem(ctx, "menu_item_difficulty_single", 520,(1024 - 520)/2,400,scrW,scrH); 
    middleBarrel = new MenuItem(ctx, "middle_barrel_single", 323,(1024-323)/2,200,scrW,scrH); 

    playIntent = new Intent(context, GameActivity.class); 
    playIntent.putExtra("screenWidth", screenWidth); 
    playIntent.putExtra("screenHeight", screenHeight); 
} 

@Override 
public void run() { 
    while (running){ 
     draw(); 
    } 
} 

private void draw() { 
    if(surfaceHolder.getSurface().isValid()){ 
     canvas = surfaceHolder.lockCanvas(); 

     canvas.drawBitmap(bg.getBmp(), bg.getSourceRect(), bg.getDestRect(), null); 
     canvas.drawBitmap(menuItemPlay.getBmp(), menuItemPlay.getSourceRect(), menuItemPlay.getDestRect(), null); 
     canvas.drawBitmap(menuItemDifficulty.getBmp(), menuItemDifficulty.getSourceRect(), menuItemDifficulty.getDestRect(), null); 
     canvas.drawBitmap(middleBarrel.getBmp(), middleBarrel.getSourceRect(), middleBarrel.getDestRect(), null); 

     surfaceHolder.unlockCanvasAndPost(canvas); 
    } 
} 

public void resume(){ 
    running = true; 
    thread = new Thread(this); 
    thread.start(); 
} 

public void pause(){ 
    running = false; 
    boolean retry = false; 
    while (retry) { 
     try { 
      thread.join(); 
      retry = false; 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
      Log.d("info", "MainActivitySurface: Error joining thread"); 
     } 
    } 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    switch (event.getAction() & event.ACTION_MASK){ 
     case MotionEvent.ACTION_UP: 
      if (menuItemPlay.contains((int) event.getX(), (int) event.getY())){ 
       app.playTap(); 
       parentActivity.startActivity(playIntent); 
       parentActivity.overridePendingTransition(0,0); 
       break; 
      } 
      if (menuItemDifficulty.contains((int) event.getX(), (int) event.getY())){ 
       app.playTap(); 
       difficultyIntent = new Intent(parentActivity, DifficultyActivity.class); 
       difficultyIntent.putExtra("screenWidth", screenWidth); 
       difficultyIntent.putExtra("screenHeight", screenHeight); 
       difficultyIntent.putExtra("difficulty", difficulty); 
       parentActivity.startActivityForResult(difficultyIntent, 1001); 
       parentActivity.overridePendingTransition(0, 0); 
       break; 
      } 
    } 
    return true; 
} 

public void setParentActivity(Activity act){ 
    parentActivity = act; 
} 

public void setResultDifficulty(int diff){ 
    difficulty = diff; 
    playIntent.putExtra("difficulty", difficulty); 
} 
} 

DifficultyActivity

public class DifficultyActivity extends Activity { 

private DifficultySurface surface; 
private globalApp app; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    //Setting full screen 
    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 

    View decorView = getWindow().getDecorView(); 
    int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 
    decorView.setSystemUiVisibility(uiOptions); 

    app = (globalApp) getApplication(); 

    surface = new DifficultySurface(this, app, getIntent().getIntExtra("screenWidth", 500), getIntent().getIntExtra("screenHeight", 500)); 
    setContentView(surface); 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
    app.soundPool.release(); 
    surface.pause(); 
    overridePendingTransition(0, 0); 
} 

@Override 
protected void onResume() { 
    super.onResume(); 
    app.buildSoundPool(); 
    app.loadSounds(); 
    surface.resume(); 
} 
} 

DifficultySurface

public class DifficultySurface extends SurfaceView implements Runnable { 

private SurfaceHolder surfaceHolder; 
private Thread thread = null; 
private Canvas canvas; 
private Context context; 
private globalApp app; 

private boolean surfaceCreated = false; 
private boolean running = false; 

private MenuItem bgProp, arrowBarrel, okButton, diffVeryEasy, diffEasy, diffNormal, diffHard, diffVeryHard; 

private int difficulty; 

public DifficultySurface(Context ctx, globalApp a, int scrW, int scrH){ 
    super(ctx); 

    context = ctx; 

    app = a; 

    surfaceHolder = getHolder(); 

    surfaceHolder.addCallback(new SurfaceHolder.Callback() { 
     @Override 
     public void surfaceCreated(SurfaceHolder holder) { 
      surfaceCreated = true; 
     } 

     @Override 
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 

     } 

     @Override 
     public void surfaceDestroyed(SurfaceHolder holder) { 

     } 
    }); 

    difficulty = ((Activity)context).getIntent().getIntExtra("difficulty", 3); 

    bgProp = new MenuItem(ctx, "difficulty_background", 1024, 0, 0, scrW, scrH); 

    diffVeryEasy = new MenuItem(ctx, "very_easy",796, 100, 100, scrW, scrH); 
    diffEasy = new MenuItem(ctx, "easy",796, 100, 200 , scrW, scrH); 
    diffNormal = new MenuItem(ctx, "normal",796, 100, 300, scrW, scrH); 
    diffHard = new MenuItem(ctx, "hard",796, 100, 400 , scrW, scrH); 
    diffVeryHard = new MenuItem(ctx, "very_hard",796, 100, 500, scrW, scrH); 
    okButton = new MenuItem(ctx, "ok_button", 100, 924, 500, scrW, scrH); 

    arrowBarrel = new MenuItem(ctx, "barrel_arrow", 100, 0, 100*difficulty, scrW, scrH); 
} 

@Override 
public void run() { 
    while (running) { 
     if (surfaceCreated) { 
      update(); 
      draw(); 
     } 
    } 
} 

private void update() { 
    arrowBarrel.setY(difficulty*100); 
} 

private void draw() { 

    if (surfaceHolder.getSurface().isValid()){ 
     canvas = surfaceHolder.lockCanvas(); 


     canvas.drawBitmap(bgProp.getBmp(), bgProp.getSourceRect(), bgProp.getDestRect(), null); 

     canvas.drawBitmap(arrowBarrel.getBmp(), arrowBarrel.getSourceRect(), arrowBarrel.getDestRect(), null); 

     canvas.drawBitmap(diffVeryEasy.getBmp(), diffVeryEasy.getSourceRect(), diffVeryEasy.getDestRect(), null); 
     canvas.drawBitmap(diffEasy.getBmp(), diffEasy.getSourceRect(), diffEasy.getDestRect(), null); 
     canvas.drawBitmap(diffNormal.getBmp(), diffNormal.getSourceRect(), diffNormal.getDestRect(), null); 
     canvas.drawBitmap(diffHard.getBmp(), diffHard.getSourceRect(), diffHard.getDestRect(), null); 
     canvas.drawBitmap(diffVeryHard.getBmp(), diffVeryHard.getSourceRect(), diffVeryHard.getDestRect(), null); 

     canvas.drawBitmap(okButton.getBmp(), okButton.getSourceRect(), okButton.getDestRect(), null); 

     surfaceHolder.unlockCanvasAndPost(canvas); 
    } 

} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    switch (event.getAction() & event.ACTION_MASK){ 
     case MotionEvent.ACTION_UP:{ 
      if (diffVeryEasy.contains((int) event.getX(), (int) event.getY())){ 
       app.playTap(); 
       difficulty = 1;    } 
      if (diffEasy.contains((int) event.getX(), (int) event.getY())){ 
       app.playTap(); 
       difficulty = 2; 
      } 
      if (diffNormal.contains((int) event.getX(), (int) event.getY())){ 
       app.playTap(); 
       difficulty = 3; 
      } 
      if (diffHard.contains((int) event.getX(), (int) event.getY())){ 
       app.playTap(); 
       difficulty = 4; 
      } 
      if (diffVeryHard.contains((int) event.getX(), (int) event.getY())){ 
       app.playTap(); 
       difficulty = 5; 
      } 
      if (okButton.contains((int)event.getX(), (int) event.getY())){ 
       app.playTap(); 
       ((Activity)context).getIntent().putExtra("difficulty", difficulty); 
       ((Activity)context).setResult(Activity.RESULT_OK, ((Activity)context).getIntent()); 
       ((Activity)context).finish(); 
       ((Activity)context).overridePendingTransition(0, 0); 
      } 
      break; 
     } 
    } 
    return true; 
} 

public void pause(){ 
    running = false; 
    boolean retry = true; 
    while (retry) { 
     try { 
      thread.join(); 
      retry = false; 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
    ((Activity)context).overridePendingTransition(0, 0); 
} 

public void resume(){ 
    running = true; 
    thread = new Thread(this); 
    thread.start(); 
} 
} 

GameActivity

public class GameActivity extends Activity { 

private GameSurface surface; 
private globalApp app; 

private int difficulty; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    //Setting full screen 
    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 

    View decorView = getWindow().getDecorView(); 
    int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 
    decorView.setSystemUiVisibility(uiOptions); 

    difficulty = getIntent().getIntExtra("difficulty", 3); 

    app = (globalApp) getApplication(); 

    surface = new GameSurface(this, app, getIntent().getIntExtra("screenWidth", 500), getIntent().getIntExtra("screenHeight", 500), difficulty); 

    surface.setParentActivity(this); 

    setContentView(surface); 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
    app.soundPool.release(); 
    surface.pause(); 
} 

@Override 
protected void onPostResume() { 
    super.onPostResume(); 
    app.buildSoundPool(); 
    app.loadSounds(); 
    surface.resume(); 
} 

@Override 
protected void onStop() { 
    super.onStop(); 
    surface.stop(); 
} 

@Override 
public void onBackPressed() { 
    super.onBackPressed(); 
    finish(); 
} 
} 

ゲームの停止私はDificultyActivityを起動したときに(私は1つのMenuItemオブジェクトをタップするが、何も起こらない)、または私は(ゲームはまだMainActivity + MainActivitySurfaceを示し)GameActivityを起動したときのいずれかが起こります。

Androidモニターは割り当てられたメモリが40MB未満であるため、私の意見ではビットマップは問題ではないはずです。私はすべてのビットマップをリサイクルしようとしましたが、問題が存在しました(そのため、mdpi drawablesのみを使用することにしました;最初はすべてのピクセル密度を使用しましたが、

+0

フレームレートに関するコンソール上のメッセージは表示されますか? – VVB

+0

あなたはlogcatを意味しますか?もしそうなら、いいえ。ゲームが停止したときに私が言ったのは、ログに表示されている唯一のものであるという意味のGCメッセージだけでした。ゲームがうまくいっている間にGCのメッセージがログに記録されていることに気がついたので、GCを停止しているのはそれだけだとは思わない。 – Dragan

+0

ログstraceを送信する – VVB

答えて

0

私は私の問題を解決しました。質問を投稿した後、私はthisに出くわしました。同じ問題があったようです。描画速度を遅くすると(thread.sleepを使用)、それ以上の問題はありませんでした。

私を助けてくれたおかげです。

0

コードを見ることなく問題を見つけるのは難しいです。リソースを処理するためのノーガット特有の方法はありません。

しかし、アンドロイドNはメモリ管理が優れていると主張しています。ガベージコレクションに多くの不満を抱いているため、原因の1つになる可能性があります。未使用のビットマップは必ずリサイクルしてください。また、RGB_888よりも半分のメモリを必要とする優先ビットマップ設定としてRGB_565を使用してください。

関連する問題