Android应用程序不断崩溃到OutOfMemoryError

时间:2015-10-27 14:24:50

标签: java android android-layout android-studio

我的应用程序一直在崩溃,我无法理解它的错误,到处寻找答案,据我所知,人们说是因为设备内存不足,我不明白是什么原因造成的?

  1. 是因为我的res / drawable文件夹中的图像太多了吗?
  2. 是因为我的res / drawable文件夹中有一个相当高分辨率的图像?
  3. 如果问题是上述问题之一,解决方案是什么?把图像放在assets文件夹中还是什么?下面是错误堆栈。 谢谢。

    MainActivity.java

    public class MainActivity extends Activity {
    
    Class <? extends Activity> classVariable;
    int last_level;
    TextView text_play, text_level, game_title;
    RelativeLayout playBtn, levelBtn;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        playBtn = (RelativeLayout) findViewById(R.id.playBtn);
        levelBtn = (RelativeLayout) findViewById(R.id.levelBtn);
        game_title = (TextView) findViewById(R.id.game_title);
        text_play = (TextView) findViewById(R.id.text_play);
        text_level = (TextView) findViewById(R.id.text_level);
    
        Typeface tf  = Typeface.createFromAsset(getAssets(), "fonts/snap-itc.ttf");
        text_play.setTypeface(tf);
        text_level.setTypeface(tf);
        game_title.setTypeface(tf);
    
        // Check if file exists
        File file = getBaseContext().getFileStreamPath("levels.json");
        if (file.exists()) {
            // Get the JSON Object from the data
            JSONObject parent = this.parseJSONData();
    
            try {
                last_level = parent.getInt("level");
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    
        switch (last_level) {
            case 1:
                classVariable = Level002Activity.class;
                break;
            case 2:
                classVariable = Level003Activity.class;
                break;
            case 3:
                classVariable = Level004Activity.class;
                break;
            case 5:
                classVariable = Level005Activity.class;
                break;
            default:
                classVariable = Level001Activity.class;
        }
    
        playBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(getApplicationContext(),
                        Level002Activity.class);
                startActivity(i);
            }
        });
    
        levelBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent in = new Intent(getApplicationContext(),
                        Level001Activity.class);
                startActivity(in);
            }
        });
    
    }
    
    public JSONObject parseJSONData() {
        String JSONString = null;
        JSONObject jsonObject = null;
        try {
            // Open the inputStream to the file
            FileInputStream fin = openFileInput("levels.json");
    
            int sizeOfJSONFile = fin.available();
    
            // array that will store all the data
            byte[] bytes = new byte[sizeOfJSONFile];
    
            // reading data into the array from the file
            fin.read(bytes);
    
            // close the input stream
            fin.close();
    
            JSONString = new String(bytes, "UTF-8");
            jsonObject = new JSONObject(JSONString);
    
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (JSONException x) {
            x.printStackTrace();
            return null;
        }
        return jsonObject;
    }
    
    }
    

    调用ChooseLevelActivity.class

    时会一直显示错误

    ChooseLevelActivity.java

    public class ChooseLevelActivity extends Activity implements View.OnClickListener {
    
    ImageView level001, level002, level003, level004, level005;
    int last_level, best_move;
    String best_time, level_selected;
    TextView levelName, bestMove, bestTime;
    Class <? extends Activity> classVariable;
    Button playBtn;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.choose_level);
    
        level001 = (ImageView) findViewById(R.id.level001);
        level002 = (ImageView) findViewById(R.id.level002);
        level003 = (ImageView) findViewById(R.id.level003);
        level004 = (ImageView) findViewById(R.id.level004);
        level005 = (ImageView) findViewById(R.id.level005);
    
        levelName = (TextView) findViewById(R.id.level_name);
        bestMove = (TextView) findViewById(R.id.best_move);
        bestTime = (TextView) findViewById(R.id.best_time);
        playBtn = (Button) findViewById(R.id.playBtn);
    
        // Get the JSON Object from the data
        JSONObject parent = parseJSONData("levels.json");
    
        // Array of ImageView
        final ImageView[] levelsArray = {level001, level002, level003, level004, level005};
    
        // This will store all the values inside "best_move and time" in an element string
        try {
            last_level = parent.getInt("level");
        } catch (JSONException e) {
            e.printStackTrace();
        }
    
        for(int i = 0; i < last_level; i++) {
            levelsArray[i].setVisibility(View.VISIBLE);
            levelsArray[i].setOnClickListener(this);
        }
    }
    
    @Override
    public void onClick(View v) {
    
        switch (v.getId()) {
            case R.id.level001:
                level_selected = "level001";
                classVariable = Level001Activity.class;
                break;
            case R.id.level002:
                level_selected = "level002";
                classVariable = Level002Activity.class;
                break;
            case R.id.level003:
                level_selected = "level003";
                classVariable = Level003Activity.class;
                break;
            case R.id.level004:
                level_selected = "level004";
                classVariable = Level004Activity.class;
                break;
            case R.id.level005:
                level_selected = "level005";
                classVariable = Level005Activity.class;
                break;
        }
    
        String fileName = "record_" + level_selected + ".json";
    
        // Get the JSON Object from the data
        JSONObject parents = parseJSONData(fileName);
    
        // This will store all the values inside "best_move and time" in an element string
        try {
            best_move = parents.getInt("best_move");
            best_time = parents.getString("best_time");
        } catch (JSONException e) {
           // e.printStackTrace();
        }
    
        levelName.setText("Level " + level_selected.substring(5));
        bestMove.setText("Best Move: " + best_move);
        bestTime.setText("Best Time: " + best_time);
    
        playBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(getApplicationContext(),
                        classVariable);
                startActivity(i);
                finish();
            }
        });
    
    }
    
    public JSONObject parseJSONData(String file) {
        String JSONString = null;
        JSONObject jsonObject = null;
        try {
            // Open the inputStream to the file
            FileInputStream fin = openFileInput(file);
    
            int sizeOfJSONFile = fin.available();
    
            // array that will store all the data
            byte[] bytes = new byte[sizeOfJSONFile];
    
            // reading data into the array from the file
            fin.read(bytes);
    
            // close the input stream
            fin.close();
    
            JSONString = new String(bytes, "UTF-8");
            jsonObject = new JSONObject(JSONString);
    
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (JSONException x) {
            x.printStackTrace();
            return null;
        }
        return jsonObject;
    }
    }
    

    错误堆栈:

    Process: com.example.ed.pieces, PID: 12939
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.ed.pieces/com.example.ed.pieces.Level001Activity}: android.view.InflateException: Binary XML file line #289: Binary XML file line #289: Error inflating class <unknown>
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
            at android.app.ActivityThread.-wrap11(ActivityThread.java)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:148)
            at android.app.ActivityThread.main(ActivityThread.java:5417)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    Caused by: android.view.InflateException: Binary XML file line #289: Binary XML file line #289: Error inflating class <unknown>
            at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
            at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:393)
            at android.app.Activity.setContentView(Activity.java:2166)
            at com.example.ed.pieces.Level001Activity.onCreate(Level001Activity.java:62)
            at android.app.Activity.performCreate(Activity.java:6237)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
            at android.app.ActivityThread.-wrap11(ActivityThread.java)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:148)
            at android.app.ActivityThread.main(ActivityThread.java:5417)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    
    Caused by: android.view.InflateException: Binary XML file line #289: Error inflating class <unknown>
            at android.view.LayoutInflater.createView(LayoutInflater.java:645)
            at com.android.internal.policy.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:58)
            at android.view.LayoutInflater.onCreateView(LayoutInflater.java:694)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:762)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:835)
            at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:838)
            at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:838)
            at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
            at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:393)
            at android.app.Activity.setContentView(Activity.java:2166)
            at com.example.ed.pieces.Level001Activity.onCreate(Level001Activity.java:62)
            at android.app.Activity.performCreate(Activity.java:6237)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
            at android.app.ActivityThread.-wrap11(ActivityThread.java)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:148)
            at android.app.ActivityThread.main(ActivityThread.java:5417)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    
    
     Caused by: java.lang.reflect.InvocationTargetException
            at java.lang.reflect.Constructor.newInstance(Native Method)
            at android.view.LayoutInflater.createView(LayoutInflater.java:619)
            at com.android.internal.policy.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:58)
    Caused by: java.lang.OutOfMemoryError: Failed to allocate a 10240012 byte allocation with 4194304 free bytes and 7MB until OOM
            at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
            at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
            at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
            at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1080)
            at android.content.res.Resources.loadDrawableForCookie(Resources.java:2635)
            at android.content.res.Resources.loadDrawable(Resources.java:2540)
            at android.content.res.TypedArray.getDrawable(TypedArray.java:870)
            at android.view.View.<init>(View.java:3948)
            at android.widget.ImageView.<init>(ImageView.java:145)
            at android.widget.ImageView.<init>(ImageView.java:140)
            at android.widget.ImageView.<init>(ImageView.java:136)
    

2 个答案:

答案 0 :(得分:1)

内存不足错误

当您为处理多个图像集或大位图或某些动画内容的应用程序开发时,内存不足错误是非常常见的错误。在这种情况下,我们必须在处理图像或对象分配和释放时非常小心和高效。当分配超过堆限制或您的进程需要超过堆限制的内存量时,会出现OOM错误。

在Android中,每个应用程序都在Linux进程中运行。每个Linux进程都在其中运行虚拟机(Dalvik虚拟机)。进程可以要求的内存有一个限制,它对于不同的设备是不同的,并且对于手机和平板电脑也是不同的。当某个进程需要比其限制更高的内存时,会导致错误,即内存不足错误。

尝试这可以帮助您在清单文件中添加此标记。

android:largeHeap="true"

它将为您的应用分配大堆

要将Drawable转换为位图,请使用此

Drawable myDrawable = getResources().getDrawable(R.drawable.logo);
Bitmap myLogo = ((BitmapDrawable) myDrawable).getBitmap();

使用此方法,您可以解码图像

public static Bitmap decodeImageFile(File f,int WIDTH,int HIGHT){
             try {
                 //Decode image size
                 BitmapFactory.Options o = new BitmapFactory.Options();
                 o.inJustDecodeBounds = true;
                 BitmapFactory.decodeStream(new FileInputStream(f),null,o);

                 //The new size we want to scale to
                 final int REQUIRED_WIDTH=WIDTH;
                 final int REQUIRED_HIGHT=HIGHT;
                 //Find the correct scale value. It should be the power of 2.
                 int scale=1;
                 while(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HIGHT)
                     scale*=2;

                 //Decode with inSampleSize
                 BitmapFactory.Options o2 = new BitmapFactory.Options();
                 o2.inSampleSize=scale;
                 return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
             } catch (FileNotFoundException e) {}
             return null;
            }

然后在使用此方法的地方调用此方法:

Bitmap b = decodeImageFile(f, 1280, 720);

答案 1 :(得分:0)

如果您的图像分辨率很高,我建议您使用缓冲区加载图像。

String defCoverPath = "drawable/" + "def_cover" + ".png";
yourView.setBackgroundDrawable(LoadResourceImage(defCoverPath));


public static BitmapDrawable LoadResourceImage(String resPath){
        AssetManager assets = MyApp.GetContext().getResources().getAssets();
        BitmapDrawable bitmapDrawable = new BitmapDrawable();

        try {
            InputStream buffer = new BufferedInputStream((assets.open(resPath)));
            Bitmap bitmap = BitmapFactory.decodeStream(buffer);
            bitmapDrawable = new BitmapDrawable(MyApp.GetContext().getResources(), bitmap);
        }catch (FileNotFoundException e){
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return bitmapDrawable;
    }