应用程序在重新启动活动时崩溃

时间:2016-08-02 06:35:30

标签: android android-activity memory-leaks

我发现了一些有同样错误的帖子。但是,他们都没有为我的问题提供有效的解决方案。

我有两个活动类,MainActivity和GameActivity。 MainActivity按下按钮启动GameActivity。如果我按下手机上的后退按钮,它将返回主要活动。但是,当我再次按下按钮以启动新的GameActivity时,系统会提示我指向代码行的错误

setContentView(R.layout.activity_game);

错误:

08-02 02:16:56.365 2220-2220/joseph.imbroglio E/AndroidRuntime: FATAL EXCEPTION: main
Process: joseph.imbroglio, PID: 2220
    java.lang.RuntimeException: Unable to start activity ComponentInfo{joseph.imbroglio/joseph.imbroglio.GameActivity}: android.view.InflateException: Binary XML file line #7: Error inflating class <unknown>
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2661)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
    at android.app.ActivityThread.access$900(ActivityThread.java:172)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1421)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:145)
    at android.app.ActivityThread.main(ActivityThread.java:5835)
    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:1399)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
    Caused by: android.view.InflateException: Binary XML file line #7: Error inflating class <unknown>
    at android.view.LayoutInflater.createView(LayoutInflater.java:640)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:750)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:813)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:511)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:415)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:366)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:428)
    at android.app.Activity.setContentView(Activity.java:2241)
    at joseph.imbroglio.GameActivity.onCreate(GameActivity.java:30)
    at android.app.Activity.performCreate(Activity.java:6221)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2614)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) 
    at android.app.ActivityThread.access$900(ActivityThread.java:172) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1421) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:145) 
    at android.app.ActivityThread.main(ActivityThread.java:5835) 
    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:1399) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194) 
    Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Constructor.newInstance(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:288)
    at android.view.LayoutInflater.createView(LayoutInflater.java:614)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:750) 
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:813) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:511) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:415) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:366) 
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:428) 
    at android.app.Activity.setContentView(Activity.java:2241) 
    at joseph.imbroglio.GameActivity.onCreate(GameActivity.java:30) 
    at android.app.Activity.performCreate(Activity.java:6221) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2614) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) 
    at android.app.ActivityThread.access$900(ActivityThread.java:172) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1421) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:145) 
    at android.app.ActivityThread.main(ActivityThread.java:5835) 
    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:1399) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194) 
    Caused by: java.lang.OutOfMemoryError: Failed to allocate a 72000012 byte allocation with 16777216 free bytes and 65MB until OOM
    at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:726)
    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:547)
    at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:575)
    at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:605)
    at joseph.imbroglio.Entity.<init>(Entity.java:42)
    at joseph.imbroglio.Face.<init>(Face.java:13)
    at joseph.imbroglio.GameView.init(GameView.java:67)
    at joseph.imbroglio.GameView.<init>(GameView.java:52)
    at java.lang.reflect.Constructor.newInstance(Native Method) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:288) 
    at android.view.LayoutInflater.createView(LayoutInflater.java:614) 
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:750) 
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:813) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:511) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:415) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:366) 
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:428) 
    at android.app.Activity.setContentView(Activity.java:2241) 
    at joseph.imbroglio.GameActivity.onCreate(GameActivity.java:30) 
    at android.app.Activity.performCreate(Activity.java:6221) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2614) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) 
    at android.app.ActivityThread.access$900(ActivityThread.java:172) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1421) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:145) 
    at android.app.ActivityThread.main(ActivityThread.java:5835) 
    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:1399) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194) 

MainActivity的onCreate方法:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
    mainActivity = this;
    playbtn = (ImageView) findViewById(R.id.imageView);
    final Intent intent = new Intent(getBaseContext(), GameActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    playbtn.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            playbtn.setImageResource(R.drawable.playbutton2);
            startActivity(intent);
            getIntent().removeExtra("startTest");
            return true;
        }
    });
}

GameActivity的onCreate方法:

public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_game);

    gameView = (GameView)findViewById(R.id.gameView);
    gameView.setGameActivity(this);
    gameThread = new Thread(gameView);
    gameThread.start();
    MainActivity.resetButton();
}

activity_game XML文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="joseph.imbroglio.GameActivity"
    android:layout_width="match_parent"     android:layout_height="match_parent">

    <joseph.imbroglio.GameView
        android:id="@+id/gameView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <TextView
        android:text="TextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/textView"
        android:textSize="24sp"
        android:textColor="?android:attr/colorBackground" />
</RelativeLayout>

该resetButton方法的代码:

public static void resetButton(){
    playbtn.setImageResource(R.drawable.playbutton);
}

根据要求,这里是GameView类的代码:

import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;

import java.util.ArrayList;

/**
 * Created by root on 7/4/16.
 */
public class GameView extends SurfaceView implements Runnable,     SurfaceHolder.Callback{

protected Resources resources;

private SurfaceHolder holder;

protected ArrayList<Entity> entities = new ArrayList<Entity>();

private long lastUpdate = 0;

protected GameActivity ga;

private Background background;
private Player player;
private Face face;
private TileSet tileSet;
private ArrayList<Fruit> fruits = new ArrayList<Fruit>();

private boolean surfaceCreated = false;
private boolean hasActiveHolder = false;
private boolean touchingRight = false;
private boolean touchingLeft = false;

private int accel = getResources().getDisplayMetrics().widthPixels/25;

private Physics physics;


public GameView(Context context){
    super(context);
    init();
}

public GameView(Context context, AttributeSet attrs){
    super(context, attrs);
    init();
}

public GameView(Context context, AttributeSet attrs, int defStyle){
    super(context, attrs, defStyle);
    init();
}

public void init(){
    //this.setBackgroundColor(Color.RED);
    //setWillNotDraw(false);
    resources = this.getResources();
    holder = getHolder();
    background = new Background(this, R.drawable.background, 1);
    player = new Player(this, R.drawable.yellowtest, 4);
    face = new Face(this, R.drawable.face, 8);
    tileSet = new TileSet(this);
    populateFruits();
    entities.add(background);
    entities.add(player);
    entities.add(face);
    entities.addAll(tileSet.getTiles());
    entities.addAll(fruits);
    holder.addCallback(this);
    physics = new Physics(entities);
    setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {

            if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
                if(motionEvent.getX() >= getResources().getDisplayMetrics().widthPixels/2){
                    touchingRight = true;
                } else {
                    touchingLeft = true;
                }
                return true;
            }
            if(motionEvent.getAction() == MotionEvent.ACTION_UP){
                touchingLeft=false;
                touchingRight=false;
                player.neutralize();
                return true;
            }
            return false;
        }
    });
}

public void draw(){
    synchronized (this) {
        while(!hasActiveHolder){
            try{
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Canvas canvas = holder.lockCanvas();
        if(canvas != null) {
            paintCanvas(canvas);
            holder.unlockCanvasAndPost(canvas);
        }
    }
}

public void paintCanvas(Canvas canvas){
    for(Entity e : entities){
        e.draw(canvas);
    }
    tileSet.tileDead(fruits);
    tileSet.checkFell(player.pos);
    player.animation1();
    face.eat();
}

@Override
public void run() {

    while(ga.playing){
        if((System.currentTimeMillis() - lastUpdate) < 16){
            try {
                Thread.sleep(Math.abs(16 - (System.currentTimeMillis()-lastUpdate)));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if(this.surfaceCreated) {
            physics.update();
            manage();
            draw();
            lastUpdate = System.currentTimeMillis();
        }

    }
}

@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
    surfaceCreated = true;
    synchronized (this) {
        hasActiveHolder = true;
        this.notifyAll();
    }
}

@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

}

@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    surfaceCreated=false;
    synchronized (this){
        hasActiveHolder = false;

        synchronized(this){
            this.notifyAll();
        }
    }
}

public int getPlayerX(){
    return player.x;
}

public int getPlayerY(){
    return player.y;
}

public Player getPlayer(){
    return player;
}

public void manage(){
    if(player.x > (getResources().getDisplayMetrics().widthPixels - player.width)){
        player.x = getResources().getDisplayMetrics().widthPixels - player.width;
    }
    if(player.x < 0){
        player.x = 0;
    }
    face.x = player.x;
    //if((!touchingLeft) && (!touchingRight)){
        //player.ax = 0;
    //}
    if(player.isAlive()) {
        if (touchingRight) {
            player.ax += accel;
        }
        if (touchingLeft) {
            player.ax -= accel;
        }
    }

}

public void populateFruits(){
    for(int i = 0; i < 20; i++){
        fruits.add(new Fruit(this, R.drawable.fruit, 2, getResources().getDisplayMetrics().widthPixels/20, getResources().getDisplayMetrics().widthPixels/20));
    }
}

public Face getFace(){
    return face;
}

public void setGameActivity(GameActivity gl){
    ga = gl;
}

}

有关此问题的任何意见?

2 个答案:

答案 0 :(得分:0)

我认为您用于应用的图片尺寸可能不支持您的手机。尽量减少图像的大小。

答案 1 :(得分:0)

假设您的GameActivity第一次正确启动,但在按BACK(返回MainActivity)然后启动GameActivity崩溃(由于OutOfMemory)后,可能意味着GameActivity的原始实例结束时,您没有正确完成清理工作。

根据您发布的代码,您可能会发生内存泄漏。这段代码:

gameView = (GameView)findViewById(R.id.gameView);
gameView.setGameActivity(this);
gameThread = new Thread(gameView);
gameThread.start();

将对gameView的引用传递给gameThreadgameView引用了GameActivity的实例。如果您在Thread的实例关闭时未正确清除此GameActivity,则垃圾收集器将无法回收旧的GameActivity及其所有资源(包括您尝试启动第二个实例之前的图像)。您可以使用堆分析和堆调试工具来帮助您找到这样的内存泄漏。