【发布时间】:2016-08-07 23:41:02
【问题描述】:
我最近做了一个游戏。当我接近完成它时,我开始在开始新活动时遇到 OutOfMemory 问题。在 Android Studio 中检查内存监视器后,我注意到我的活动在完成后仍保留在内存中。如何释放更多内存?
编辑:
我发现了另一个线程,其中提到它可能只是调试器在内存中保存了死活动。我尝试在没有调试器的情况下运行我的应用程序,但在内存不足之前我仍然只能打开和退出一项记分牌活动和两场游戏,因为这些活动在退出后仍在内存中。我做了一个跟踪,finish() 和 onDestroy() 被调用了。
目前,根据 AS 中的内存监视器,我的 MainMenu 活动使用大约 90 MB 并分配了 100。当我开始游戏时,它会跳到 165 已使用,然后从游戏返回并开始新游戏显示 230ish 已使用。之后开始更多游戏会使内存使用量保持在 230 左右,但如果我打开记分板,它会崩溃,因为它需要大约 60mb 并且只有 20mb 可用空间并且分配超过 256mb 会使应用程序崩溃。如果我先打开记分牌,然后玩 2 场比赛,也会发生同样的事情。这些数字比我希望的要高,我正在寻找减少每个活动的 ram 使用量的方法,但我现在主要关心的是在活动完成后释放 ram。
程序流程相当简单,Activity A 是主菜单,它可以启动 Activity B 及以上。除了 A 之外的活动不能开始一个新的活动。 B 和 up 之间没有通信,都是由 A 启动并返回 Intent 给 A。
由于项目有点大,我不能真正发布所有代码,但这里是我如何从 A 开始一个 ScoreboardActivity 并在我的记分牌类中从 B 返回意图。 (由于我尝试删除引用,活动有些臃肿)
从 Activity A:如果用户单击 ID 为 3 的按钮,则启动记分板:
if ( id == 3) {
scoreboardIntent = new Intent(getApplicationContext(), ScoreBoard.class);
startActivityForResult(scoreboardIntent, 0);
}
这里 A 接收来自记分板的结果。 A 确实没有充分的理由得到结果,但我添加了这个以查看是否可以在 onResult() 回调中释放内存,但所有其他活动确实需要返回结果)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (data.hasExtra("resultpage")) {
scoreboardIntent = null;
return;
}
这是记分牌的类文件:
public class ScoreBoard extends AppCompatActivity implements AdapterView.OnItemClickListener, View.OnClickListener {
ScoreAdapter adapter;
Firebase myFirebase;
DataSnapshot scoreSnapshot;
DataSnapshot noviceSnapshot;
DataSnapshot expertSnapshot;
String difficulty = "novice";
ArrayList<Score> scores = new ArrayList<Score>();
ArrayList<Score> noviceScores = new ArrayList<Score>();
ArrayList<Score> expertScores = new ArrayList<Score>();
ListView listView;
int clicked = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scoreboard_layout);
myFirebase = new Firebase(myFirebaseUri);
getScoresFromFirebase();
listView = (ListView) findViewById(R.id.scoreboardlist);
RadioButton b1 = (RadioButton)findViewById(R.id.button1);
RadioButton b2 = (RadioButton)findViewById(R.id.button2);
b1.setOnClickListener(this);
b2.setOnClickListener(this);
scores = noviceScores;
listView.setOnItemClickListener(this);
adapter = null;
listView.setAdapter(null);
adapter = new ScoreAdapter(this, R.layout.scoreboard_item, scores);
listView.setAdapter(adapter);
adapter.setNotifyOnChange(true);
}
private DataSnapshot getScoresFromFirebase() {
...
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {}
@Override
public void onBackPressed() {
Intent returnIntent = new Intent();
returnIntent.putExtra("resultpage",0);
setResult(Activity.RESULT_OK,returnIntent);
//For the heck of it I decided to null out everything I could
adapter.clear();
adapter = null;
myFirebase = null;
scoreSnapshot = null;
noviceSnapshot = null;
expertSnapshot = null;
difficulty = null;
scores = null;
noviceScores = null;
expertScores = null;
listView = null;
getIntent().setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
finish();
super.finish();
}
@Override
public void onClick(View v) {
if (v.getId() == clicked) return;
clicked = v.getId();
//Show topscores for easy mode
if (v.getId() == R.id.button1) {
scores = noviceScores;
adapter = null;
listView.setAdapter(null);
adapter = new ScoreAdapter(this, R.layout.scoreboard_item, scores);
listView.setAdapter(adapter);
Animation anim = AnimationUtils.loadAnimation(
this, android.R.anim.slide_in_left
);
anim.setDuration(350);
listView.startAnimation(anim);
}
//show topscores for hard mode
if (v.getId() == R.id.button2) {
scores = expertScores;
adapter = null;
listView.setAdapter(null);
adapter = new ScoreAdapter(this, R.layout.scoreboard_item, scores);
listView.setAdapter(adapter);
}
}
}
【问题讨论】:
标签: java android android-activity memory