我正在制作益智游戏,每次用户完成拼图时,都会出现一个重新创建按钮,它只是调用recreate()方法来重启拼图活动。
我覆盖了onSaveInstanceState,因为我想保存为拼图选择的图像,以及在屏幕方向改变的情况下保存4个图像。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("originalBM", originalBm);
outState.putParcelable("bm1", bm1);
outState.putParcelable("bm2", bm2);
outState.putParcelable("bm3", bm3);
outState.putParcelable("bm4", bm4);
}
因此,当用户单击“重新创建”按钮时,正在调用recreate()方法,默认情况下也调用onSaveInstanceState,因为这是android的工作原理,用户必须一次又一次地使用相同的图像来玩拼图。
我不想实现与onCreate方法相同的代码来选择新的随机图像,因为这会导致内存泄漏,并且在10-12重新创建后我的应用程序崩溃了。
我只是希望它重新启动活动干净清爽!
我没有在我的recreatePuzzle方法中使用recreate(),而是还尝试了这个
Intent intent = getIntent();
finish();
startActivity(intent);
但这再次导致我的应用在10-12重新创建后崩溃。它也导致内存泄漏。
所以,我认为最好的方法是在调用我的recreatePuzzle时跳过覆盖saveInstanceState(如果可能)或者在调用onSaveInstanceState时传递null Bundle。
有没有办法实现上述任何解决方案?
任何帮助都将受到高度赞赏。
提前谢谢大家。
编辑:
我班级的完整代码
package kidsbook.jok.kidsbook;
public class Puzzle extends AppCompatActivity {
private String[] puzzleIMGS;
private String randomPuzzleIMG;
private int corrects = 0, tries = 0;
private ImageView part1, part2, part3, part4;
private TextView piece1, piece2, piece3, piece4;
private Button againButton;
private Bitmap bm1, bm2, bm3, bm4, originalBm;
private Intent i;
private MediaPlayer mp = new MediaPlayer();
private List<Bitmap> parts = new ArrayList<>();
private boolean recreatePuzzle = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_puzzle);
mp = MediaPlayer.create(getApplicationContext(), R.raw.pop);
//Select random image
puzzleIMGS = getResources().getStringArray(R.array.all_animal_imgs);
randomPuzzleIMG = puzzleIMGS[new Random().nextInt(puzzleIMGS.length)];
//Get all elements
againButton = (Button) findViewById(R.id.againPuzzleButton);
part1 = (ImageView) findViewById(R.id.part1);
part2 = (ImageView) findViewById(R.id.part2);
part3 = (ImageView) findViewById(R.id.part3);
part4 = (ImageView) findViewById(R.id.part4);
piece1 = (TextView) findViewById(R.id.piece1);
piece2 = (TextView) findViewById(R.id.piece2);
piece3 = (TextView) findViewById(R.id.piece3);
piece4 = (TextView) findViewById(R.id.piece4);
part1.setOnTouchListener(new MyTouchListener());
part2.setOnTouchListener(new MyTouchListener());
part3.setOnTouchListener(new MyTouchListener());
part4.setOnTouchListener(new MyTouchListener());
piece1.setOnDragListener(new MyDragListener());
piece2.setOnDragListener(new MyDragListener());
piece3.setOnDragListener(new MyDragListener());
piece4.setOnDragListener(new MyDragListener());
if(savedInstanceState!=null) {
Log.i("debug","inside saved instance");
//Convert randomly selected resource image to bitmap
originalBm = savedInstanceState.getParcelable("originalBM");
bm1 = savedInstanceState.getParcelable("bm1");
bm2 = savedInstanceState.getParcelable("bm2");
bm3 = savedInstanceState.getParcelable("bm3");
bm4 = savedInstanceState.getParcelable("bm4");
} else {
Log.i("debug","inside null instance");
//Convert randomly selected resource image to bitmap
originalBm = BitmapFactory.decodeResource(getResources(), getImageId(this, randomPuzzleIMG));
//Split bitmap to 4 parts
bm1 = Bitmap.createBitmap(originalBm, 0, 0, (originalBm.getWidth() / 2), (originalBm.getHeight() / 2));
bm2 = Bitmap.createBitmap(originalBm, (originalBm.getWidth() / 2), 0, (originalBm.getWidth() / 2), (originalBm.getHeight() / 2));
bm3 = Bitmap.createBitmap(originalBm, 0, (originalBm.getHeight() / 2), (originalBm.getWidth() / 2), (originalBm.getHeight() / 2));
bm4 = Bitmap.createBitmap(originalBm, (originalBm.getWidth() / 2), (originalBm.getHeight() / 2), (originalBm.getWidth() / 2), (originalBm.getHeight() / 2));
}
//Make the background transparent
piece1.setBackgroundDrawable(new BitmapDrawable(getResources(), bm1));
piece1.setAlpha(0.2f);
piece2.setBackgroundDrawable(new BitmapDrawable(getResources(), bm2));
piece2.setAlpha(0.2f);
piece3.setBackgroundDrawable(new BitmapDrawable(getResources(), bm3));
piece3.setAlpha(0.2f);
piece4.setBackgroundDrawable(new BitmapDrawable(getResources(), bm4));
piece4.setAlpha(0.2f);
//Place parts in an array
parts.add(bm1);
parts.add(bm2);
parts.add(bm3);
parts.add(bm4);
//Shuffle the array
Collections.shuffle(parts);
//Assign the correct piece tag to each part
for(int i=0;i<4;i++){
if(i==1) {
part1.setImageBitmap(parts.get(i));
if (parts.get(i).equals(bm1)){
part1.setTag("piece1");
} else if (parts.get(i).equals(bm2)){
part1.setTag("piece2");
} else if (parts.get(i).equals(bm3)){
part1.setTag("piece3");
} else {
part1.setTag("piece4");
}
} else if(i==2){
part2.setImageBitmap(parts.get(i));
if (parts.get(i).equals(bm1)){
part2.setTag("piece1");
} else if (parts.get(i).equals(bm2)){
part2.setTag("piece2");
} else if (parts.get(i).equals(bm3)){
part2.setTag("piece3");
} else {
part2.setTag("piece4");
}
} else if(i==3){
part3.setImageBitmap(parts.get(i));
if (parts.get(i).equals(bm1)){
part3.setTag("piece1");
} else if (parts.get(i).equals(bm2)){
part3.setTag("piece2");
} else if (parts.get(i).equals(bm3)){
part3.setTag("piece3");
} else {
part3.setTag("piece4");
}
} else {
part4.setImageBitmap(parts.get(i));
if (parts.get(i).equals(bm1)){
part4.setTag("piece1");
} else if (parts.get(i).equals(bm2)){
part4.setTag("piece2");
} else if (parts.get(i).equals(bm3)){
part4.setTag("piece3");
} else {
part4.setTag("piece4");
}
}
}
}
private static int getImageId(Context context, String imageName) {
return context.getResources().getIdentifier("drawable/" + imageName, null, context.getPackageName());
}
private final class MyTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
ClipData data = ClipData.newPlainText("", "");
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
view.startDrag(data, shadowBuilder, view, 0);
return true;
} else {
return false;
}
}
}
class MyDragListener implements View.OnDragListener {
@Override
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
switch (action) {
case DragEvent.ACTION_DRAG_STARTED:
// do nothing
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
// Dropped, reassign View to ViewGroup
View view = (View) event.getLocalState();
ViewGroup owner = (ViewGroup) view.getParent();
if(view.getTag().equals(v.getTag())){
if(view.getTag().equals("piece1")){
owner.removeView(view);
useMediaPlayer();
piece1.setBackgroundDrawable(new BitmapDrawable(getResources(), bm1));
piece1.setAlpha(0.9f);
corrects++;
} else if (view.getTag().equals("piece2")){
owner.removeView(view);
useMediaPlayer();
piece2.setBackgroundDrawable(new BitmapDrawable(getResources(), bm2));
piece2.setAlpha(0.9f);
corrects++;
} else if (view.getTag().equals("piece3")){
owner.removeView(view);
useMediaPlayer();
piece3.setBackgroundDrawable(new BitmapDrawable(getResources(), bm3));
piece3.setAlpha(0.9f);
corrects++;
} else if (view.getTag().equals("piece4")) {
owner.removeView(view);
useMediaPlayer();
piece4.setBackgroundDrawable(new BitmapDrawable(getResources(), bm4));
piece4.setAlpha(0.9f);
corrects++;
}
}
tries++;
if(corrects==4){
finish();
}
break;
case DragEvent.ACTION_DRAG_ENDED:
break;
default:
break;
}
return true;
}
}
public void useMediaPlayer(){
mp.start();
}
public void againPuzzle(View v){
recreatePuzzle = true;
recreate();
}
public void finish(){
againButton.setVisibility(View.VISIBLE);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("originalBM", originalBm);
outState.putParcelable("bm1", bm1);
outState.putParcelable("bm2", bm2);
outState.putParcelable("bm3", bm3);
outState.putParcelable("bm4", bm4);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_games, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
switch(item.getItemId()){
case android.R.id.home:
i = new Intent(this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
return true;
case R.id.menu_about:
i = new Intent(this, About.class);
startActivity(i);
return true;
case R.id.menu_help:
i = new Intent(this, Help.class);
startActivity(i);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onBackPressed() {
i = new Intent(this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
}
答案 0 :(得分:0)
开始相同的活动然后完成前一个活动怎么样?喜欢:
Intent intent=new Intent(this, MainActivity.class)
startActivity(intent);
finish();
使用finish将帮助您不像oncreate()那样有任何内存泄漏。
第二个选项:移动代码以新方法选择拼图(如selectNewPuzzle()),然后在onCreated中调用该方法,并在需要时选择一个新拼图。
第三个选项:使用名为&#34; canSaveInstance&#34;的全局布尔值。当onCreate结束时,这是真的。将实例状态保存在if语句中,并检查此布尔值,并且当您需要重新创建时,将此变量设置为false,重新设置为正常情况(因此不会保存数据,启动新拼图)然后将其重新设置为true(以处理配置)变化)。在重新创建活动时,您需要小心:if(savedinstancestate!= null)必须变为&#34; if(savedinstancestate!= null&amp;&amp; canSaveInstance)(因为如果不是,您可能会尝试加载之前未保存的数据) )。
最后一个选项:(但我并不真正意识到如何做到这一点)阻止用户多次启动拼图活动,然后&#34;启动&#34;一个新的(我认为旧的将被超越)。你可能需要做更多的研究才能做到这一点。由于其他选项更容易,我不会搜索帮助这样做的文档。
答案 1 :(得分:0)
所以我终于想出了一个解决方案。我缺少的是释放我的活动的位图内存,这是导致内存泄漏的原因。所以,最后,我重新创建()方法看起来像
public void againPuzzle(View v){
originalBm.recycle();
bm1.recycle();
bm2.recycle();
bm3.recycle();
bm4.recycle();
originalBm = null;
bm1 = null;
bm2 = null;
bm3 = null;
bm4 = null;
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);
}