重新创建传递硬编码的空实例状态的活动

时间:2017-04-23 03:40:42

标签: android android-activity memory-leaks recreate onsaveinstancestate

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

2 个答案:

答案 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);
}