Memory problems when loading many images in listview

Asked

Viewed 221 times

2

I made an application where it is possible to take a photo and save its path in the database and then show in a listview along with other information. Everything goes well when there are few images or small images to be displayed, but when arriving at a certain amount of images, the application is very slow arriving sometimes until it stops. This is the error that occurs:

FATAL EXCEPTION: main java.lang.Outofmemoryerror: Failed to allocate a 20155404 byte allocation with 16777120 free and 16MB until OOM.

class to capture or select sd card image

 public class InicialMy extends Activity {
 private static final int SELECT_PICTURE = 1;
 private static final int CAPTURAR_IMAGEM = 2;
 private static final int REQUEST_IMAGE_PICK = 3;
 private Uri uri;
 private Button irParaLista;

 private String caminho;
 private TextView lugar;
 private String imagePath;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_inicial_my);
        Button save = (Button)findViewById(R.id.button);



        File imgFile = new File("/storage/emulated/0/Download/20150617-0013.jpeg");

        if(imgFile.exists()){
            Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
            ImageView miImage = (ImageView) findViewById(R.id.imageCapa);
            miImage.setImageBitmap(myBitmap);
        }

        save.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Controller dao = new Controller(getBaseContext());

                irParaLista = (Button)findViewById(R.id.buttonLista);

                EditText nome = (EditText)findViewById(R.id.editTextTitulo);
                EditText dono = (EditText)findViewById(R.id.editTextAutor);
                ImageView foto = (ImageView)findViewById(R.id.imageCapa);

                String result;

                result = dao.insereDado(nome.getText().toString(),dono.getText().toString(),caminho);
                Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
            }
        });

        Button btn = (Button) findViewById(R.id.buttonImage);
        btn.setOnClickListener(mOnClickListener);
    }

    //começo do button
    private View.OnClickListener mOnClickListener = new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            Intent intent = new Intent();
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_PICK);
            startActivityForResult(Intent.createChooser(intent, "Selecione a capa do livro"), REQUEST_IMAGE_PICK);
        }
    };
    //fim do button
    public void lista(View view){
        if(view.getId() == R.id.buttonLista){
            startActivity(new Intent(this, ListaCarros.class));
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent){
        super.onActivityResult(requestCode, resultCode, intent);

        switch (requestCode){
        case REQUEST_IMAGE_PICK:
            if(RESULT_OK == resultCode){
                Uri imageUri = intent.getData();

                ImageView imagemCapa = (ImageView) findViewById(R.id.imageCapa);
                imagemCapa.setImageURI(imageUri);
                imagePath = getImagePath(imageUri);
                Toast.makeText(this, imagePath, Toast.LENGTH_LONG).show();
                caminho = imagePath;

            }
        break;
        case CAPTURAR_IMAGEM:
             if(requestCode == CAPTURAR_IMAGEM){
                mostrarMensagem("Imagem capturada");
                adicionarNaGaleria();
            }

        }
    }


    public String getImagePath(Uri contentUri){
        String [] campos = {MediaStore.Images.Media.DATA};
        Cursor cursor = getContentResolver().query(contentUri, campos, null, null, null);
        cursor.moveToFirst();
        String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
        cursor.close();
        return path;
    }


    private void adicionarNaGaleria(){
        Intent intent = new Intent(
                    Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
                );
        intent.setData(uri);
        this.sendBroadcast(intent);
    }

    private void mostrarMensagem(String msg){
        Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
    }

    public void capturarImagem(View view){
        File diretorio = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

        String nomeImagem = diretorio.getPath()+"/"+System.currentTimeMillis()+".jpg";

        uri = Uri.fromFile(new File(nomeImagem));

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);

        startActivityForResult(intent, CAPTURAR_IMAGEM);
    }
    public void visualizarImagem(View view){
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(uri, "image/jpeg");
        startActivity(intent);
    }

 }

class to display the list:

public class ListaCarros extends ActionBarActivity {
private CarrosAdapter adaptador;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_lista_carros);
    List<Carro> lista;
    ListView controle;
    Controller dao = new Controller(getBaseContext());
    Cursor cursor = dao.carregaDados();
    lista = cursor2List(cursor);
    adaptador = new CarrosAdapter(getApplication(),R.layout.layout_carros, lista);
    controle = (ListView)findViewById(R.id.listView);
    controle.setAdapter(adaptador);
}

protected List<Carro> cursor2List(Cursor cursor){
    List<Carro> carros = new ArrayList<Carro>();
    cursor.moveToFirst();
    do{
        Carro carro = new Carro();

        carro.setNome(cursor.getString(cursor.getColumnIndex(DBHelper.NOME)));
        carro.setDono(cursor.getString(cursor.getColumnIndex(DBHelper.DONO)));
        carro.setFoto(cursor.getString(cursor.getColumnIndex(DBHelper.FOTO)));

        carros.add(carro);
    }while(cursor.moveToNext());
    return carros;
}
}

class to control data entry:

public class Controller {

 private SQLiteDatabase db;
    private DBHelper banco;

    public Controller(Context context){
        banco = new DBHelper(context);
    }

    public String insereDado(String nome, String dono,  String caminho){
        ContentValues valores;
        long resultado;
        db = banco.getWritableDatabase();

        valores = new ContentValues();
        valores.put(banco.NOME,nome);
        valores.put(banco.DONO,dono);
        valores.put(banco.FOTO,caminho);
        resultado = db.insert(banco.TABELA,null,valores);
        db.close();

        if(resultado==-1){
            return "ERRO";
        }else{
            return "Inserido com Sucesso";
        }
    }
    public Cursor carregaDados(){
        Cursor cursor;
        String[] campos =  {banco.ID,banco.NOME,banco.DONO,banco.FOTO};
        db = banco.getReadableDatabase();
        cursor = db.query(banco.TABELA, campos, null, null, null, null, null, null);

        if(cursor!=null){
            cursor.moveToFirst();
        }
        db.close();
        return cursor;
    }
 }

Adapter cars:

public class CarrosAdapter extends ArrayAdapter<Carro>{
Context contexto;
int id;
List<Carro> lista;
public CarrosAdapter(Context contexto, int id, List<Carro> lista){
    super(contexto,id,lista);
    this.contexto = contexto;
    this.lista = lista;
    this.id = id;

}

public View getView(int position, View convertView, ViewGroup parent){
    View view = convertView;
    Carro carro;
    ImageView foto;
    TextView nome;
    TextView dono;
    Bitmap raw;
    TextView caminho;

    if(view == null){
        LayoutInflater inflater = LayoutInflater.from(contexto);
        view = inflater.inflate(id, parent, false);
    }

    nome = (TextView)view.findViewById(R.id.textView);
    dono = (TextView)view.findViewById(R.id.textView3);
    foto = (ImageView)view.findViewById(R.id.imageView);
    caminho = (TextView)view.findViewById(R.id.textViewCaminho);

    carro = lista.get(position);

    nome.setText(carro.getNome());
    dono.setText(carro.getDono());

    File imgFile = new File(carro.getFoto());
    Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath()); 

    foto.setImageBitmap(myBitmap);



    caminho.setText(carro.getFoto());

    return view;
}
}

Can someone help me solve this memory problem?

2 answers

2


This happens because when working with pictures on Android a great memory amount is allocated and you’d have to treat it instead of going straight to setImageBitmap(myBitmap);
I suggest you use helpdesk libraries like Glide, Picasso and etc searching on Google you think a lot. Try this.
In your Gradle add:

compile 'com.squareup.picasso:picasso:2.5.2'

Then on your Adapter change

  ...nome = (TextView)view.findViewById(R.id.textView);
dono = (TextView)view.findViewById(R.id.textView3);
foto = (ImageView)view.findViewById(R.id.imageView);
caminho = (TextView)view.findViewById(R.id.textViewCaminho);

carro = lista.get(position);

nome.setText(carro.getNome());
dono.setText(carro.getDono());

Picasso.with(context). load(new File(carro.getFoto())). into(foto);

caminho.setText(carro.getFoto());...

You can do a lot of things with these libs: Crop, cash etc... follow the lib doc Picasso Doc

  • And good that you use Crop also this optimizes a lot

  • thanks for the help, really was of great help, I’m already looking for (like crazy) by these libraries! thank you very much

0

I am not going to give you a complete solution because that would imply writing a tutorial.
To solve the problem of Outofmemoryerror replace the line

Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath()); 

for

BitmapFactory.Options options = new BitmapFactory.Options();

//Comece com 2 mas experimente valores maiores de acordo com a sua necessidade, 
//quanto maior o valor menor a memória necessária mas mais pequena será a imagem.
options.inSampleSize = 2;//O valor deverá ser uma potência de 2: 2, 4, 8, 16, etc.

Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), options);

The Bitmap generated will be a reduced version of the original whose size is a function of the value assigned to inSampleSize.

When solving the error Outofmemoryerror other problems will arise so I advise you to read the documentation here and here

I could point out to you ready-made libraries that solve these problems for you but I think it’s more interesting if you first learn how things work.

  • thanks for the help, really improved the speed and I’m already reading the documentation to avoid other errors. thank you very much!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.