Memory problems loading many images into listView

2

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

  

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

class to capture or select the 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 show 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 the insertion of data:

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;
    }
 }

car adapter:

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 anyone help me solve this memory problem?

    
asked by anonymous 27.12.2015 / 02:36

2 answers

2

This happens because when working with images on Android a large amount of memory is allocated and you would have to treat it instead of going straight to setImageBitmap (myBitmap); >
I suggest you use help libraries like Glide, Picasso and etc. by searching Google you think enough. 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 (car.getFoto ()). into (photo);

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

You can do several things with these libs: crop, cash etc ... follow the doc of the Picasso Doc

    
27.12.2015 / 16:20
0

I'm not going to give you a complete solution because this would involve writing a tutorial. To resolve the OutOfMemoryError replace line

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

by

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 will be a reduced version of the original whose size is a function of the inSampleSize value.

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

I could point you to ready libraries that solve these problems for you but I think it's more interesting if you first learned how things work.

    
27.12.2015 / 16:21