2016-05-07 2 views
0

Я пишу приложение для Android, которое требует больших объемов памяти и испытывает проблемы с нехваткой памяти. Приложение имеет два вида деятельности. Основное действие использует серия кнопок, которые используют обработчики событий для загрузки разных изображений в ImageViews во втором действии. Когда пользователь нажимает кнопку «Назад назад», приложение возвращается к основному действию.Android App OutOfMemory Ошибка

Проблема, с которой я столкнулся, заключается в том, что в конечном итоге приложение вылетает с ошибкой OutOfMemory.

На следующем графике показано использование памяти моего приложения, когда я перемещаюсь между двумя действиями. Сделав этот снимок экрана, я попытался еще раз открыть второе действие с помощью одной из кнопок, и ошибка снова возникла. Вы заметите, что последний горб находится дальше от остальных. Это потому, что я остановился на секунду, чтобы сделать снимок экрана с ожиданием, что следующая попытка приведет к его краху. Когда это не было, я снова снял фотографии.

Android App Memory Usage Graph

Я бы предположил, что проблема может быть решена путем явного принуждения деятельности, чтобы освободить память, когда они не используются. Проблема в том, что я не делаю этого, и не могу найти четкого объяснения в строке, где подробно описано, как это можно сделать.

Вот пример кода от просмотра изображения деятельности:

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Point; 
import android.os.Bundle; 
import android.os.Environment; 
import android.support.v7.app.AppCompatActivity; 
import android.support.v7.widget.Toolbar; 
import android.view.View; 
import android.widget.ImageView; 
import android.widget.TableRow; 

import java.io.File; 

public class ViewPost extends AppCompatActivity { 
    Context appContext = this; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_view_image); 
     Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
     setSupportActionBar(toolbar); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 

     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       final ImageView imgPhoto = (ImageView) findViewById(R.id.imgPhoto); 
       final TableRow photoLayout = (TableRow) findViewById(R.id.photoLayout); 

       // Get the width of the device screen. 
       Point screenDimensionFinder = new Point(); 
       getWindowManager().getDefaultDisplay().getSize(screenDimensionFinder); 
       final int screenWidth = screenDimensionFinder.x; 

       runOnUiThread(new Runnable() { 
        @Override 
        public void run() { 
         File imageFolder = new File(String.valueOf(appContext.getExternalFilesDir(
           Environment.DIRECTORY_PICTURES))); 
         File photoFile = new File(imageFolder, "P" + Integer.toString(postId) + 
           ".jpg"); 
         if(photoFile.exists()) { 
          Bitmap image = BitmapFactory.decodeFile(photoFile.getAbsolutePath()); 
          imgPhoto.setImageBitmap(resizeBitmap(image, screenWidth)); 
         } 
         else { 
          photoLayout.setVisibility(View.GONE); 
         } 
        } 
       }); 
      } 
     }).start(); 
    } 

    private Bitmap resizeBitmap(Bitmap image, int screenWidth) 
    { 
     // Resize the bitmap so that it fits on the screen, while preserving its aspect ratio. 
     int imageWidth = image.getWidth(); 
     int imageHeight = image.getHeight(); 
     int imageNewHeight = (imageHeight * screenWidth)/imageWidth; 
     image = Bitmap.createScaledBitmap(image, screenWidth, imageNewHeight, false); 
     return image; 
    } 
} 
+0

Можете ли вы опубликовать коды двух видов деятельности! – varunkr

+0

@varunkr Какую часть вы хотели бы видеть? Я не хочу публиковать все это. (т. е. обработчики событий для кнопок, обработка изображений) – DavidB

+0

Поскольку вы размещаете изображения, очевидно, что это источник ошибки, однако для определения точной проблемы мне нужно будет посмотреть код. – varunkr

ответ

1

Вы должны попытаться использовать эту функцию для декодирования файла. Этот метод загружает уменьшенную версию растрового изображения с использованием переменной inSampleSize, которая уменьшает потребление памяти.

private Bitmap decodeFile(File f){ 
    Bitmap b = null; 

     //Decode image size 
    BitmapFactory.Options o = new BitmapFactory.Options(); 
    o.inJustDecodeBounds = true; 

    FileInputStream fis = new FileInputStream(f); 
    BitmapFactory.decodeStream(fis, null, o); 
    fis.close(); 

    int scale = 1; 
    if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) { 
     scale = (int)Math.pow(2, (int) Math.ceil(Math.log(IMAGE_MAX_SIZE/
      (double) Math.max(o.outHeight, o.outWidth))/Math.log(0.5))); 
    } 

    //Decode with inSampleSize 
    BitmapFactory.Options o2 = new BitmapFactory.Options(); 
    o2.inSampleSize = scale; 
    fis = new FileInputStream(f); 
    b = BitmapFactory.decodeStream(fis, null, o2); 
    fis.close(); 

    return b; 
} 
+0

Спасибо! Не могли бы вы объяснить мне, что такое 'IMAGE_MAX_SIZE'? Является ли это той же функцией, которую я вижу на этой странице (http://developer.android.com/training/displaying-bitmaps/manage-memory.html) в заголовке «Использовать существующий битмап»? – DavidB

+0

@DavidB Нет, decodeFile там и один в вашем коде просто используют реализацию по умолчанию в классе BitmapFactory, которая не заботится об этом. В этом методе изображение масштабируется соответствующим образом, чтобы предотвратить ошибки памяти. IMAGE_MAX_SIZE - это новый размер, который вы хотите масштабировать до размера вашего изображения. – varunkr

+0

@DavidB Также я должен сказать это, чтобы прояснить ваши сомнения в вопросе. Уничтожение активности не гарантирует, что память будет очищена. Для этого вам нужно очистить процесс, который вы никогда не должны делать, вместо этого оставите его в ОС. – varunkr

0

У меня была такая же проблема. Я решил это, используя Пикассо по квадрату. Picasso.with (getContext()). Load (imageResId) .fit(). CenterInside(). В (imageView);

Вам нужно будет изменить способ загрузки, но он поддерживает загрузку (файл f).

+0

Спасибо, но, к сожалению, мне не разрешено использовать сторонние библиотеки для этого проекта. – DavidB

Смежные вопросы