last day (15 days later) » 

9:15 PM
0
Q: Erro OutOfMemoryError ao baixar lista de objetos

JuarezEstou com este erro ao baixar um objeto do webservice que possui imagens que estão convertidas na base64. A questão é que se esse objeto ja estiver salvo no banco de dados local do android o app funciona, consigo carregar muitos objetos ao mesmo tempo e mostrar na tela, mas agora estou baixando d...

 
Acontece isso no emulador 2.3 por que sua memoria é pequena. Ja testei em um dispositvo com o s.o 2.3 e acontece esse erro. Eu não entendo por que eu acho que não chega nem a 2 MB as imagens do objeto que da o erro, isso é muito pouco.
Inicialmente eu baixava o arrayList com todos os objetos. Dai testei no dispositivo com android 2.3 e o erro apresentou, fiz um algoritimo para baixar 1 por 1, funcionou, mas mesmo assim eu tenho que tomar cuidado ao cadastrar os objetos no webservice, pois se as imagens forem mts pesadas o erro vai acontecer.
O que eu fico intrigado, é que eu salvo os 20 objetos tudo no Banco de Dados local do android, a imagens viram bytes e salvo no bd tbm. E quando inicio o aplicativo tudo funciona. Ou seja os objetos são carregados todos em memória ao mesmo tempo.
 
Juarez, será que não nenhum tipo de buffer que é criado muito grande ou algo interno de alguma biblioteca/api que está usando? Como está tratando o retorno da resposta do webservice?
 
@Wakim adicionei um método que faz o download. Se puder analiza-lo.
 
Juarez, como você está convertendo essa String de resposta em Bitmap? Porque não usa o BufferedHttpEntity junto com o BitmapFactory.decodeStream para gerar o Bitmap? Acredito que usando o BitmapFactory seja bem mais performático, mas não tenho certeza, só com um teste.
 
Funciona assim @Wakim, nesse caso não crio Bitmap, eu só faço o download e guardo direto no bd local, transformar em Bitmap é só na hora de pegar no bd local e mostrar na tela, ai eu uso métodos do BitmapFactory.decodeStream . Isso ja tratei. o problema é na hora do download, eu recebo os objetos, em json, a imagens vem em Base64, decodo elas para array de bytes e salvo no BD, até ai não há necessidade de gerar Bitmap. O estouro de memória está acontecendo enquanto acontece o download.Tenho q tomar cuidado para não enviar imagens ou um conjunto de imagens que somando da um tam. grande em MB.
 
9:15 PM
Hmm, entendi... Você lê todo o JSON e depois processa. Você consegue modificar a resposta do seu WebService? A minha sugestão seria fazer uma resposta customizada, para poder evitar carregar tudo na memória antes de processar. Minha ideia é colocar cada objeto em uma linha, usando o readLine para processar um objeto de cada vez, sem deixar na memória. Ficaria algo assim: {...}\n\r{...}\n\r{...}.
 
Imagens maiores que 1MB eu não envio pois elas não salvam no bd SQLite, o problema então é um conjunto de imagens que envio, vamos supor se um objeto tem 10 imagens de 500KB ai ja estoura.
Exatamente @Wakim ja fiz um jeito de enviar um objeto por vez. Mas tenho que tomar cuidado pra esse objeto não possuir um nmr grande de imagens, isso ainda eu nao consegui tratar. A solução pode ser enviar as imagens de cada vez, mas seria um algoritmo mt complexo e um custo maior de requisição.Ou então "tisorar" os celulares com android 2.3 sendo que existe mt pouco.
A solução momentanea é limitar um nmr max de imagens (5) para um objeto, e com limite de tamanho de 500KB cada foto.
 
Como está a configuração de memória do dispositivo que roda na VM (AVD)? 5 MB é bastante coisa considerando a versão 2.3 com um dispositivo low-end. Posso dar uma olhada se existe alguma limitação em termos práticos em algum lugar da documentação. Além disso, você usa o Android Studio? Nele existe uma ferramenta (nova) que mostra o gráfico de consumo de memória do aplicativo, seria uma boa ver se consegue usar para ver em que momento a memória sobe a ponto de estourar o heap. Tente também usar as ferramentas do ddms, que mostra o consumo.
 
Uso o eclipse, mas consigo importar o projeto no Android Studio. Vou dar uma olhada nisso. Eu testei no genymotion, e com o emulador padrão, e em um celular real versão 2.3.
 
Não achei nada que diga exatamente, mas dizem que dispositivos antigos tem limitação de 16 MB (o que é pouco considerando tudo: Views, Activity's, Fragments, e tudo mais): stackoverflow.com/questions/18675557/…. Mas você pode consultar usando o método: developer.android.com/reference/android/app/…. Outro cuidado é usar o recycle (developer.android.com/reference/android/graphics/…) assim que não precisar mais de um Bitmap e evitar leak's de memória com Bitmaps.
 
@Wakim fiz um teste aqui debugando, coloquei um objeto com 10 imagens de 300kb cada, a aplicação baixa tudo sem erro, não tinha prestado atenção. O estouro de memoria está acontecendo aqui while((line = br.readLine())!=null) la no metodo inputStreamParaString
 
9:17 PM
Mas faz sentido dar o OutOfMemoryError no readLine, porque ele tenta alocar memória internamente. O ideal é tentar fazer uma função que retorne o maior número de imagens que possam ser baixadas para um determinado dispositivo/memória restante. Afim de não estourar mas também não ficar fazendo requisições excessivas. Se seu back-end consiga fazer essa conta, passando a quantidade de MB que o dispositivo tem livre (dando uma certa margem).
Acho que essa questão do cálculo, pode ser feito com um certo esfoço, porque você sabe quanto cada String ocupa de memória, considerando o número de caracteres. Você pode pegar um objeto e calcular quantas imagens cabem de uma só vez e fazer a paginação se não couber todas as imagens.
 

last day (15 days later) »