0

我正在制作一个益智游戏,每次用户完成拼图时,都会出现一个重新创建按钮,它只是调用 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 时传递一个空 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);
}
}
4

2 回答 2

0

开始同一个活动然后完成前一个活动怎么样?喜欢 :

Intent intent=new Intent(this, MainActivity.class)
startActivity(intent);
finish();

使用完成将帮助您不会像 oncreate() 那样出现任何内存泄漏。

第二个选项:移动代码在新方法中选择一个谜题(如 selectNewPuzzle()),然后在 onCreated 中调用该方法,并在需要时选择一个新谜题。

第三个选项:使用名为“canSaveInstance”的全局布尔值,当 onCreate 结束时为真。将保存 instancestate 的行封装在 if 语句中检查这个布尔值,当你需要重新创建时,把这个变量设置为 false,像往常一样重新创建(所以不保存数据,开始新的拼图)然后将其设置为 true(处理配置变化)。重新创建活动时需要小心: if(savedinstancestate!=null) 必须变为 "if(savedinstancestate!=null && canSaveInstance) (因为如果不是,您可能会尝试加载以前未保存的数据)。

最后一个选项:(但我真的不知道如何做)阻止用户多次启动拼图活动,然后“启动”一个新的(我认为旧的将被覆盖)。你可能需要做更多的研究来做这个。由于其他选项更容易,我不会搜索帮助这样做的文档。

于 2017-04-23T03:59:15.240 回答
0

所以我终于想出了一个解决方案。我缺少的是释放我活动的位图内存,这就是导致内存泄漏的原因。所以,最后,我的 recreate() 方法看起来像

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);
}
于 2017-04-23T23:27:43.620 回答