Я пытаюсь сделать игровое приложение. У меня есть 3 вида деятельности (интро, игра / основной и геймплей). Игра работает нормально с первой по третью попытки, но в четвертый раз, пытаясь повторить попытку (есть кнопка, чтобы повторить попытку при выполнении игры, которая возвращает вас к основному действию), я получаю эту ошибку: E / art: throwing OutOfMemoryError "Не удалось выделить 27581052 байта для выделения с 7416608 свободных байтов и до OOM"
Я уже пытался: 1) изменить размер изображений / растровых изображений, с которыми я работаю; 2) поместите изображения в разные папки для рисования, такие как xhdpi, xxxhdpi (и все между ними ...); 3) добавление android:hardwareAccelerated="false"
и android:largeHeap="true"
к манифесту; И все они только что купили мне еще несколько попыток повторной попытки, но не решили проблему (приложение получает такое же сообщение об ошибке после 8 ~ 10 попыток).
Я также пробовал их, так как я нашел их на некоторых Ответы здесь, на этом форуме: 4) реализация ComponentCallbacks2 onTrimMemory (https://developer.android.com/topic/performance/memory.html) во время игры или основных действий; 5) добавление чего-то подобного в игровой процесс или в основные виды деятельности:
@Override
public void onDestroy() {
super.onDestroy();
Runtime.getRuntime().gc();
}
И это не изменило мою проблему ...
Вот Logcat:
04-26 00:22:39.665 31000-31000/com.example.theflyingdactylgameapp I/Timeline: Timeline: Activity_launch_request time:22242888
04-26 00:22:39.755 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc sticky concurrent mark sweep GC freed 2897(97KB) AllocSpace objects, 0(0B) LOS objects, 5% free, 121MB/128MB, paused 548us total 6.523ms
04-26 00:22:39.775 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 137MB to 128MB
04-26 00:22:39.775 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc partial concurrent mark sweep GC freed 1719(109KB) AllocSpace objects, 0(0B) LOS objects, 5% free, 121MB/128MB, paused 394us total 13.719ms
04-26 00:22:39.795 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 136MB to 128MB
04-26 00:22:39.795 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc concurrent mark sweep GC freed 1089(84KB) AllocSpace objects, 0(0B) LOS objects, 5% free, 120MB/128MB, paused 473us total 21.972ms
04-26 00:22:39.795 31000-31000/com.example.theflyingdactylgameapp I/art: Forcing collection of SoftReferences for 26MB allocation
04-26 00:22:39.815 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 136MB to 128MB
04-26 00:22:39.815 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc concurrent mark sweep GC freed 12(384B) AllocSpace objects, 0(0B) LOS objects, 5% free, 120MB/128MB, paused 386us total 17.719ms
04-26 00:22:39.815 31000-31000/com.example.theflyingdactylgameapp E/art: Throwing OutOfMemoryError "Failed to allocate a 27581052 byte allocation with 7416672 free bytes and 7MB until OOM"
04-26 00:22:39.825 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 136MB to 128MB
04-26 00:22:39.825 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc partial concurrent mark sweep GC freed 6(192B) AllocSpace objects, 0(0B) LOS objects, 5% free, 120MB/128MB, paused 387us total 7.547ms
04-26 00:22:39.845 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 136MB to 128MB
04-26 00:22:39.845 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 5% free, 120MB/128MB, paused 368us total 17.285ms
04-26 00:22:39.845 31000-31000/com.example.theflyingdactylgameapp I/art: Forcing collection of SoftReferences for 26MB allocation
04-26 00:22:39.855 31000-31000/com.example.theflyingdactylgameapp I/art: Clamp target GC heap from 136MB to 128MB
04-26 00:22:39.855 31000-31000/com.example.theflyingdactylgameapp I/art: Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 5% free, 120MB/128MB, paused 551us total 17.798ms
04-26 00:22:39.855 31000-31000/com.example.theflyingdactylgameapp E/art: Throwing OutOfMemoryError "Failed to allocate a 27581052 byte allocation with 7416608 free bytes and 7MB until OOM"
04-26 00:22:39.855 31000-31000/com.example.theflyingdactylgameapp D/skia: --- allocation failed for scaled bitmap
04-26 00:22:39.855 31000-31000/com.example.theflyingdactylgameapp D/AndroidRuntime: Shutting down VM
04-26 00:22:39.865 31000-31000/com.example.theflyingdactylgameapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.theflyingdactylgameapp, PID: 31000
java.lang.OutOfMemoryError: Failed to allocate a 27581052 byte allocation with 7416608 free bytes and 7MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:613)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:446)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:469)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:501)
at com.example.theflyingdactylgameapp.FlyingDactylView.<init>(FlyingDactylView.java:57)
at com.example.theflyingdactylgameapp.MainActivity.onCreate(MainActivity.java:21)
at android.app.Activity.performCreate(Activity.java:6041)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1109)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2283)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2392)
at android.app.ActivityThread.access$800(ActivityThread.java:154)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1308)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5273)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
04-26 00:22:39.875 31000-31000/com.example.theflyingdactylgameapp I/Process: Sending signal. PID: 31000 SIG: 9
А вот игровая активность:
package com.example.theflyingdactylgameapp;
import ...
public class GameOverActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_over);
int score = (int) getIntent().getExtras().get("POPOINTS");
Button startGameAgain = findViewById(R.id.play_again_btn);
TextView displayScore = findViewById(R.id.displayScore);
TextView displayRecord = findViewById(R.id.displayRecord);
//update record
SharedPreferences settings =getSharedPreferences("RECORD", Context.MODE_PRIVATE);
int record = settings.getInt("RECORD", 0);
String score1;
String record1;
if (score > record) {
record = score;
record1 = Integer.toString(record);
score1 = Integer.toString(score);
displayScore.setText(String.format("POPOINTS = %s", score1));
displayRecord.setText(String.format("*NEW RECORD* = %s", record1));
SharedPreferences.Editor editor = settings.edit();
editor.putInt("RECORD", record);
editor.apply();
}
else {
record1 = Integer.toString(record);
score1 = Integer.toString(score);
displayScore.setText(String.format("POPOINTS = %s", score1));
displayRecord.setText(String.format("record = %s", record1));
}
startGameAgain.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent mainIntent = new Intent (GameOverActivity.this, MainActivity.class);
startActivity(mainIntent);
}
});
}
}
А вот основная деятельность:
package com.example.theflyingdactylgameapp;
import...
public class MainActivity extends AppCompatActivity {
private FlyingDactylView gameView;
private Handler handler = new Handler();
private final static long Interval = 30;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameView = new FlyingDactylView(this);
setContentView(gameView);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
gameView.invalidate();
}
});
}
}, 0, Interval);
}
}
, а вот представление, используемое основной деятельностью:
package com.example.theflyingdactylgameapp;
import ...
public class FlyingDactylView extends View {
private Bitmap dactyl[] = new Bitmap[2];
private int dactylX = 10;
private int dactylY;
private int dactylSpeed;
private int canvasWidth, canvasHeight;
private int popo0X, popo0Y, popo0Speed = 16;
private int popo2X, popo2Y, popo2Speed = 18;
private int popo1X, popo1Y, popo1Speed = 20;
private Bitmap popo[] = new Bitmap[2];
private int redX, redY, redSpeed = 24;
private int red1X, red1Y, red1Speed = 27;
private Bitmap redBall;
private int score, lifeCounterOfDactyl;
private boolean touch = false;
private Bitmap backgroundImage;
private Paint scorePaint = new Paint();
private Bitmap life[] = new Bitmap[2];
// creating sound
private SoundPool soundPool;
private int sound1, sound2, sound3;
// criando objetos na tela
public FlyingDactylView(Context context) {
super(context);
dactyl[0] = BitmapFactory.decodeResource(getResources(), R.drawable.dactyl1);
dactyl[1] = BitmapFactory.decodeResource(getResources(), R.drawable.dactyl2);
backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.background);
popo[0] = BitmapFactory.decodeResource(getResources(), R.drawable.popo1);
popo[1] = BitmapFactory.decodeResource(getResources(), R.drawable.popo2);
redBall = BitmapFactory.decodeResource(getResources(), R.drawable.red_ball);
scorePaint.setColor(Color.WHITE);
scorePaint.setTextSize(70);
scorePaint.setTypeface(Typeface.DEFAULT_BOLD);
scorePaint.setAntiAlias(true);
life[0] = BitmapFactory.decodeResource(getResources(), R.drawable.egg);
life[1] = BitmapFactory.decodeResource(getResources(), R.drawable.broken_egg);
dactylY = 550;
score = 0;
lifeCounterOfDactyl = 3;
// creating sound player and placing sounds
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build();
soundPool = new SoundPool.Builder()
.setMaxStreams(5)
.setAudioAttributes(audioAttributes)
.build();
}
else {
soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
}
sound1 = soundPool.load(this.getContext(), R.raw.fly, 1);
sound2 = soundPool.load(this.getContext(), R.raw.pick_popo, 1);
sound3 = soundPool.load(this.getContext(), R.raw.red_hit, 1);
}
// movimentos
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvasWidth = canvas.getWidth();
canvasHeight = canvas.getHeight();
canvas.drawBitmap(backgroundImage,0, 0, null);
// movimentos dactyl
int minDactylY = dactyl[0].getHeight();
int maxDactylY = canvasHeight - dactyl[0].getHeight() * 3;
dactylY += dactylSpeed;
if (dactylY < minDactylY) {
dactylY = minDactylY;
}
if (dactylY > maxDactylY) {
dactylY = maxDactylY;
}
dactylSpeed += 2;
if (touch) {
canvas.drawBitmap(dactyl[1], dactylX, dactylY, null);
touch = false;
}
else {
canvas.drawBitmap(dactyl[0], dactylX, dactylY, null);
}
// movimentos popó
popo0X -= popo0Speed;
if (hitPopoChecker(popo0X, popo0Y)) {
score += 10;
popo0X = -100;
// sound when hit popo0
soundPool.play(sound2, 1, 1,0, 0, 1);
}
if (popo0X < 0) {
popo0X = canvasWidth + 21;
popo0Y = (int) Math.floor(Math.random() * (maxDactylY - minDactylY)) + minDactylY;
}
canvas.drawBitmap(popo[0], popo0X, popo0Y, null);
// movimentos popó2
popo2X -= popo2Speed;
if (hitPopoChecker(popo2X, popo2Y)) {
score += 10;
popo2X = -100;
// sound when hit popo2
soundPool.play(sound2, 1, 1,0, 0, 1);
}
if (popo2X < 0) {
popo2X = canvasWidth + 21;
popo2Y = (int) Math.floor(Math.random() * (maxDactylY - minDactylY)) + minDactylY;
}
canvas.drawBitmap(popo[0], popo2X, popo2Y, null);
// movimentos popó gordo
popo1X -= popo1Speed;
if (hitPopoChecker(popo1X, popo1Y)) {
score += 20;
popo1X = -100;
// sound when hit popo gordo
soundPool.play(sound2, 1, 1,0, 0, 1);
}
if (popo1X < 0) {
popo1X = canvasWidth + 21;
popo1Y = (int) Math.floor(Math.random() * (maxDactylY - minDactylY)) + minDactylY;
}
canvas.drawBitmap(popo[1], popo1X, popo1Y, null);
// movimentos Red Ball
redX -= redSpeed;
if (hitPopoChecker(redX, redY)) {
redX = -100;
lifeCounterOfDactyl--;
// sound when hit red ball 1
soundPool.play(sound3, 1, 1,0, 0, 1);
if (lifeCounterOfDactyl == 0) {
Toast.makeText(getContext(), "Game Over", Toast.LENGTH_SHORT).show();
Intent gameOverIntent = new Intent(getContext(), GameOverActivity.class);
// free up resources from sound on Game Over by red ball 1
soundPool.release();
soundPool = null;
gameOverIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
gameOverIntent.putExtra("POPOINTS", score);
getContext().startActivity(gameOverIntent);
}
}
if (redX < 0) {
redX = canvasWidth + 21;
redY = (int) Math.floor(Math.random() * (maxDactylY - minDactylY)) + minDactylY;
}
canvas.drawBitmap(redBall, redX, redY, null);
// movimentos Red Ball2
red1X -= red1Speed;
if (hitPopoChecker(red1X, red1Y)) {
red1X = -100;
lifeCounterOfDactyl--;
// sound when hit red ball 1
soundPool.play(sound3, 1, 1,0, 0, 1);
if (lifeCounterOfDactyl == 0) {
Toast.makeText(getContext(), "Game Over", Toast.LENGTH_SHORT).show();
Intent gameOverIntent = new Intent(getContext(), GameOverActivity.class);
// free up resources from sound on Game Over by red ball 2
soundPool.release();
soundPool = null;
gameOverIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
gameOverIntent.putExtra("POPOINTS", score);
getContext().startActivity(gameOverIntent);
}
}
if (red1X < 0) {
red1X = canvasWidth + 21;
red1Y = (int) Math.floor(Math.random() * (maxDactylY - minDactylY)) + minDactylY;
}
canvas.drawBitmap(redBall, red1X, red1Y, null);
// Score
canvas.drawText("Popoints: " + score, 20, 60, scorePaint);
// life counter
for (int i=0; i<3; i++) {
int x = (int) (700 + life[0].getWidth() * 1.9 * i);
int y = 10;
if (i < lifeCounterOfDactyl) {
canvas.drawBitmap(life[0], x, y, null);
}
else {
canvas.drawBitmap(life[1], x, y, null);
}
}
}
public Boolean hitPopoChecker (int x, int y) {
if (dactylX < x && x < (dactylX + dactyl[0].getWidth()) && dactylY < y && y < (dactylY + dactyl[0].getHeight())) {
return true;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
touch = true;
// decrease here to make Dactyl goes faster
dactylSpeed = -22;
// sound when tap to fly
soundPool.play(sound1, 1, 1,0, 0, 1);
}
return true;
}
}
Любой совет о том, как попытаться решить его, будет высоко оценен, спасибо!