Autore Topic: ListView out of memory  (Letto 926 volte)

Offline prezzemolo86

  • Nuovo arrivato
  • *
  • Post: 36
  • Respect: +1
    • Mostra profilo
ListView out of memory
« il: 26 Maggio 2013, 20:59:25 CEST »
0
Ciao,
ho una ListView che riempio o prendendo i dati dal db o da remoto.
Purtroppo se scrollo troppo velocemente la lista vado in out of memory. Non mi sembra normale, come dovrei gestirlo o meglio ancora evitarlo? :-(

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:ListView out of memory
« Risposta #1 il: 26 Maggio 2013, 21:56:37 CEST »
0
Ciao,
ho una ListView che riempio o prendendo i dati dal db o da remoto.
Purtroppo se scrollo troppo velocemente la lista vado in out of memory. Non mi sembra normale, come dovrei gestirlo o meglio ancora evitarlo? :-(

Strano che vada outofmemory il codice della listview. Hai per caso implementato un customadapter?
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline zorcraft

  • Utente junior
  • **
  • Post: 108
  • Respect: +5
    • Mostra profilo
  • Dispositivo Android:
    note
  • Play Store ID:
    zorcraft
Re:ListView out of memory
« Risposta #2 il: 26 Maggio 2013, 22:45:51 CEST »
0
ciao ti conviene inviare un po di codice , metti delle immagini nelle tua lista?

Offline cioppy

  • Nuovo arrivato
  • *
  • Post: 35
  • Respect: +3
    • giancarlo985
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S Plus
  • Play Store ID:
    Team Android
  • Sistema operativo:
    Linux Mint 12 - 64bit
Re:ListView out of memory
« Risposta #3 il: 26 Maggio 2013, 23:09:04 CEST »
0
In genere le listview causano OutofMemory se vengono caricate immagini. Se non ricordo male ogni app ha a disposizione 16Mb di memoria. esistono alcuni pattern che ti consentono di caricare le immagini in cache, e di cancellare qualora la memoria superi una certa dimensione. Inoltre l'ideale sarebbe quello di scaricare le immagini già in formato ridotto (giusto per visualizzare la preview) e quando l'utente clicca su una rig della lista carichi l'immagine di dimensioni maggiori.
Comunque se posti un pò di codice e fornisci altre info sulla listview ti aiutiamo a risolvere il problema. :-D

Offline prezzemolo86

  • Nuovo arrivato
  • *
  • Post: 36
  • Respect: +1
    • Mostra profilo
Re:ListView out of memory
« Risposta #4 il: 27 Maggio 2013, 13:16:03 CEST »
0
Ciao a tutti!
Sì in effetti nella lista metto pure delle immagini.
Vi posto il codice di seguito:

ACTIVITY:

Codice: [Seleziona]
public class ElencoProdottiActivity extends Activity
{

        private static String LogTag ="ElencoProdottiActivity";
        private boolean checkconnection = false;
        String type = "";
        ElencoProdottiAdapter adapter;
        ListView listView;
        MyDatabase mDb;
        ProdottoDataManager pDM;

        private File dir;

        FileManager fm;
        ElencoProdottiActivity _this;
        private MCClient client;

        private String src = "no_db";


        @Override
        public void onCreate(Bundle savedInstanceState)
        {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.elenco_prodotti);
                fm = new FileManager();
                _this = this;

                Bundle bundle = getIntent().getExtras();
                String pkg = getPackageName();// Stringa univoca per identificare i dati
                type = bundle.getString(pkg);// Recupero la stringa passata

                fm = new FileManager();
                dir = fm.createStorageDir(_this, "prodotti_"+type);


                adapter = new ElencoProdottiAdapter(this);
                listView = (ListView) findViewById(R.id.listViewProdotti);

                mDb = new MyDatabase(this);
                mDb.open();
                pDM = new ProdottoDataManager(mDb);
               
               
                List<Prodotto> prodottiDB = new ArrayList<Prodotto>();

                boolean isUpdated = false;


                /*********************CONTROLLO AGGIORNAMENTO E CONNESSIONE***************************/
                Prodotto prodotto = new Prodotto();
                prodotto.setCategoria(type);
                //Log.d(LogTag, "categoria: "+type);
                //SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy HH:mm:ss");


                Cursor c = null;
                try
                {
                        c = pDM.getLastProdottoFromCategoria(prodotto);
                        int numProd = c.getCount();
                       
                        if(numProd >0 )
                        {
                                //controllo aggiornamento

                                if(c.moveToNext())
                                {
                                        long lastupdate = c.getLong(0);


                                        long currenttime = Calendar.getInstance().getTimeInMillis();

                                        long gap =lastupdate+30*60*1000; //ultimo aggiornamento + 30 minuti in millisecondi
                                        if(gap>currenttime)
                                                isUpdated = true;

                                        //SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy HH:mm:ss");
                                        /*Date date = new Date(currenttime);
                                        Date last = new Date(lastupdate);

                                        Log.d(LogTag, "currentTime: "+sdf.format(date));
                                        Log.d(LogTag, "lastupdate: "+sdf.format(last));
                                        Log.d(LogTag, "gap: "+gap);*/


                                        client = new MCClient();
                                        //se è aggiornato o non collegato => carico dal db
                                        checkconnection = client.checkConnection(this);
                                        if(isUpdated || !checkconnection)
                                        {
                                                Cursor cProd = pDM.getProdottiFromCategoria(prodotto);
                                                try
                                                {


                                                        src = "db";
                                                        while(cProd.moveToNext())
                                                        {
                                                                prodotto = new Prodotto();
                                                                prodotto.setId(""+cProd.getInt(0));
                                                                prodotto.setCategoria(cProd.getString(1));
                                                                prodotto.setTitolo(cProd.getString(2));
                                                                prodotto.setDescrizione(cProd.getString(3));
                                                                prodotto.setPrezzo(""+cProd.getInt(4));
                                                                prodotto.setOrdine(""+cProd.getInt(5));
                                                                prodotto.setImageurl(cProd.getString(6));
                                                                adapter.add(prodotto);
                                                                prodottiDB.add(prodotto);
                                                        }
                                                        new DownloadBitmapTask().execute(prodottiDB);
                                                }
                                                finally
                                                {
                                                        cProd.close();
                                                        mDb.close();

                                                }
                                        }


                                }
                        }

                }
                finally
                {
                        if(c!=null)
                                c.close();
                }

                /***********************************************************************************/

                /***************************THREAD PER SCRICARE IN REMOTO*****************************/

                if(!isUpdated && checkconnection)
                {
                        //Toast.makeText(this, "starto il thread", Toast.LENGTH_SHORT).show();

                        Log.d(LogTag, "starto il thread");       
                        String url = URLString.URL_CATALOGO_ELENCO_PRODOTTI_TEST + type;
                        new DownloadXmlTask().execute(url);
                }
                else if(!checkconnection)
                {
                        Toast.makeText(this, "connessione assente", Toast.LENGTH_LONG).show();
                }



                /***************************************************************************/




                listView.setAdapter(adapter);
                //ElencoProdottiListener listener = new ElencoProdottiListener();
                //listView.setOnItemClickListener(listener);



        }

        /*
         * AsyncTask<Params, Progress, Result>
         */
        private class DownloadXmlTask extends
        AsyncTask<String, Void, TreeMap<Integer, Prodotto>>
        {

                /*
                 * eseguito in un thread in background si occupa di eseguire il task
                 * vero e proprio. Accetta un parametro di tipo Params (il primo generic
                 * definito) e ritorna un oggetto di tipo Result
                 */
                @Override
                protected TreeMap<Integer, Prodotto> doInBackground(String... urls) {
                        try {
                                TreeMap<Integer, Prodotto> prodotti = loadXML(urls[0]);

                                return prodotti;
                        } catch (IOException e) {
                                return null;
                        } catch (XmlPullParserException e) {
                                return null;
                        }
                }

                /*
                 * eseguito nel thread principale e si occupa di aggiornare
                 * l’interfaccia dopo l’esecuzione per mostrare i dati scaricati o
                 * calcolati nel task che vengono passati come parametro
                 */
                @Override
                protected void onPostExecute(TreeMap<Integer, Prodotto>prodotti)
                {

                        if (prodotti != null)
                        {
                                if(prodotti.size()>0)
                                {
                                        pDM.deleteProdottoFromCategoria(type);
                                }
                                List<Prodotto> lista_prodotti = new ArrayList<Prodotto>();
                                Collection<Prodotto> prod_collection = prodotti.values();
                                Iterator<Prodotto> prod_iterator= prod_collection.iterator();

                                while(prod_iterator.hasNext())
                                {
                                        Prodotto prodotto = prod_iterator.next();

                                        prodotto.setCategoria(type);
                                        adapter.add(prodotto);
                                        lista_prodotti.add(prodotto);
                                        pDM.insertProduct(prodotto);
                                       
                                }
                                new DownloadBitmapTask().execute(lista_prodotti);
                                mDb.close();
                        }

                }
        }

        private TreeMap<Integer, Prodotto> loadXML(String url) throws XmlPullParserException,
        IOException {


                InputStream is = client.connect(url);
                ElencoProdottiParser parser = new ElencoProdottiParser();

                return parser.parse(is);

        }

        /*
         * AsyncTask<Params, Progress, Result>
         */
        private class DownloadBitmapTask
        extends AsyncTask<List<Prodotto>, Void, HashMap<String, Bitmap>>
        {

                /*
                 * eseguito in un thread in background si occupa di eseguire il task
                 * vero e proprio. Accetta un parametro di tipo Params (il primo generic
                 * definito) e ritorna un oggetto di tipo Result
                 */
                @Override
                protected HashMap<String, Bitmap> doInBackground(List<Prodotto>... elenco_prodotti) {
                        try {
                                HashMap<String, Bitmap> cache = new HashMap<String, Bitmap>();
                                List<Prodotto>prodotti = elenco_prodotti[0];

                                for (Prodotto prodotto:prodotti)
                                {


                                        Bitmap bitmap;
                                        if(src.equals("db"))
                                        {
                                                Log.d(LogTag, "carico bitmap da file");
                                                bitmap = getBitmapFromFile(prodotto);
                                        }
                                        else
                                        {
                                                Log.d(LogTag, "carico bitmap da remoto");
                                                bitmap = getBitmapFromURL( prodotto);
                                        }
                                       
                                        if(bitmap!=null)
                                        {
                                                cache.put(prodotto.getId(), bitmap);
                                        }
                                        else
                                        {
                                                Log.d(LogTag, "la bitmap non esiste :( ");
                                        }


                                }

                                return cache;
                        } catch (Exception e) {
                                return null;
                        }
                }

                /*
                 * eseguito nel thread principale e si occupa di aggiornare
                 * l’interfaccia dopo l’esecuzione per mostrare i dati scaricati o
                 * calcolati nel task che vengono passati come parametro
                 */
                @Override
                protected void onPostExecute(HashMap<String, Bitmap> cache)
                {

                        if (cache != null)
                        {


                                Set<String> set = cache.keySet();
                                Iterator<String> iterator = set.iterator();


                                while (iterator.hasNext())
                                {
                                        String id_prodotto = iterator.next();
                                        Bitmap bitmap = cache.get(id_prodotto);
                                        adapter.getCacheImmagini().put(id_prodotto, bitmap);

                                }


                        }
                }

        }

        /**
         * dato un prodotto, ricava l'url dell'immagine,
         * si collega e dall'InputStream che ne ottiene crea la Bitmap e salva l'immagine in locale
         * @param prodotto
         * @return
         */
        private Bitmap getBitmapFromURL(Prodotto prodotto)
        {
                try
                {
                        String urlImage = URLString.URL_IMG_CATALOGO_ELENCO_PRODOTTI_HEADER.replace("XXX", prodotto.getImageurl());
                        URL url = new URL(urlImage);
                        HttpURLConnection connection = (HttpURLConnection) url
                                        .openConnection();
                        connection.setDoInput(true);
                        connection.connect();
                        InputStream input = connection.getInputStream();

                        Bitmap myBitmap = BitmapFactory.decodeStream(input);


                        /**************************************salvo il file******************/
                        if(fm.isExternalStorageWritable())
                        {

                                if(dir.exists())
                                {
                                        File file = new File(dir.getAbsolutePath(), prodotto.getImageurl());
                                        FileOutputStream outStream = null;
                                        try {
                                                outStream = new FileOutputStream(file);
                                                myBitmap.compress(Bitmap.CompressFormat.JPEG, 95, outStream);

                                                outStream.flush();
                                                outStream.close();

                                        } catch (FileNotFoundException e) {
                                                // TODO Auto-generated catch block
                                                e.printStackTrace();
                                        }
                                        catch (IOException e) {
                                                // TODO Auto-generated catch block
                                                e.printStackTrace();
                                        }

                                        Log.d(LogTag, "il file esiste: "+file.exists());
                                        Log.d(LogTag, "dimensione: "+file.length());
                                        Log.d(LogTag, file.getAbsolutePath());

                                }
                                else {
                                        Log.e(LogTag, "la cartella non esiste!");
                                }

                        }
                        else
                        {
                                Log.e(LogTag, "non hai i permessi di SCRITTURA sulla memory card!");
                        }



                        /***********************************************************************************/


                        return myBitmap;
                } catch (Exception e)
                {
                        e.printStackTrace();
                        return null;
                }
        }


        private Bitmap getBitmapFromFile(Prodotto prodotto)
        {
                Bitmap bitmap ;
                String fileName = prodotto.getImageurl();
                Log.d(LogTag, "fileName: "+fileName);
                if(fm.isExternalStorageReadable())
                {

                        //Log.d(LogTag, "ho i permessi di lettura");

                        //Log.d(LogTag, "path dir: "+dir.getAbsolutePath());
                        //String[] fileNames = dir.list();
                        /*
                        for(int i = 0; i<fileName.length(); i++)
                        {
                                Log.d(LogTag, "fileName: "+fileNames[i]);
                        }*/
                       
                                File file = new File(dir.getAbsolutePath(), fileName);
                                if(file.exists())
                                {
                                        Log.d(LogTag, "il file esiste: "+file.getName());
                                        try
                                        {
                                                FileInputStream fis = new FileInputStream(file);

                                                return bitmap = BitmapFactory.decodeStream(fis);
                                        }
                                        catch (FileNotFoundException fnfe)
                                        {
                                                Log.e(LogTag, fnfe.getMessage());
                                        }
                                        catch (Exception e)
                                        {
                                                Log.e(LogTag, e.getMessage());
                                        }
                                }
                                else
                                {
                                        Log.e(LogTag, "il file non esiste!");
                                }

                }
                else
                {
                        Log.e(LogTag, "non hai i permessi di LETTURA sulla memory card!");
                }


                return null;
        }


}

ADAPTER:

Codice: [Seleziona]
public class ElencoProdottiAdapter extends ArrayAdapter<Prodotto> {

        HashMap<String, Bitmap> cacheImmagini = new HashMap<String, Bitmap>();

        public ElencoProdottiAdapter(Activity context) {
                super(context, R.layout.elenco_prodotti, new ArrayList<Prodotto>());



        }




        @Override
        public View getView(int position, View convertView, ViewGroup parent) {



                LayoutInflater inflater = (LayoutInflater) getContext()
                                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

                convertView = inflater.inflate(R.layout.prodotti_row, null);


                TextView titolo = (TextView) convertView.findViewById(R.id.titolo_prodotto);
                TextView descrizione = (TextView) convertView.findViewById(R.id.descr_prodotto);
                TextView prezzo = (TextView) convertView.findViewById(R.id.prezzo_prodotto);
                ImageView image = (ImageView)convertView.findViewById(R.id.ProdottoImage);




                final Prodotto prodotto = getItem(position);

                Typeface font = Typeface.createFromAsset(this.getContext().getAssets(),
                                "font/Ford-LightExt.otf");

                titolo.setTypeface(font);
                descrizione.setTypeface(font);
                prezzo.setTypeface(font);

                titolo.setText(prodotto.getTitolo());
                descrizione.setText(prodotto.getDescrizione());
                prezzo.setText("€" + prodotto.getPrezzo());

                Bitmap bimap = cacheImmagini.get(prodotto.getId());
                if(bimap!=null)
                        {
                                image.setImageBitmap(bimap);
                               
                        }


                return convertView;
        }




        /**
         * @return the cacheImmagini
         */
        public HashMap<String, Bitmap> getCacheImmagini() {
                return cacheImmagini;
        }




        /**
         * @param cacheImmagini the cacheImmagini to set
         */
        public void setCacheImmagini(HashMap<String, Bitmap> cacheImmagini) {
                this.cacheImmagini = cacheImmagini;
        }

}




Se ho scritto porcherie vi prego correggetemi, sono ancora alle prime armi e voglio imparare a programmare in maniera efficiente ed ordinata.
Grazie in anticipo




Offline rs94

  • Utente normale
  • ***
  • Post: 227
  • Respect: +21
    • Mostra profilo
  • Dispositivo Android:
    Sony Ericsson Xperia Arc S
  • Sistema operativo:
    Windows 8
Re:ListView out of memory
« Risposta #5 il: 27 Maggio 2013, 13:25:34 CEST »
0
Intanto dovresti implementare il cosiddetto ViewHolder. E' una classe che ti permette il riciclo delle view usate, cambiando solo i dati all'interno.

Un esempio qui: http://www.jmanzano.es/blog/?p=166
L'unica certezza è il dubbio.
Dubitare di se stessi è il primo segno di intelligenza.

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:ListView out of memory
« Risposta #6 il: 27 Maggio 2013, 13:39:00 CEST »
0
Intanto dovresti implementare il cosiddetto ViewHolder. E' una classe che ti permette il riciclo delle view usate, cambiando solo i dati all'interno.

Un esempio qui: http://www.jmanzano.es/blog/?p=166

Concordo.

Ed aggiungo che la funzione getView viene richiamata per ogni elemento della View, per cui si dovrebbe evitare di fargli fare ripetutamente sempre le stesse cose sugli stessi dati (mi riferisco alla creazione del font, per esempio). Ancora di più, al suo interno si dovrebbero creare meno oggetti possibile (idealmente nessuno).
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline prezzemolo86

  • Nuovo arrivato
  • *
  • Post: 36
  • Respect: +1
    • Mostra profilo
Re:ListView out of memory
« Risposta #7 il: 27 Maggio 2013, 17:36:53 CEST »
0
ok grazie mille ragazzi.
Rivedo il tutto e vi faccio sapere. Se avete altro da consigliarmi fate pure non può che essermi utile  :D

Post unito: 27 Maggio 2013, 19:15:24 CEST
la gestione della cache delle immagini, come vi sembra?
(nel frattempo sto sistemando il ViewHolder)

Post unito: 27 Maggio 2013, 19:39:40 CEST
ragazzi!!!! Funzionaaaa!  :D
Se mi date un parere sulla cache risolvo il post  ;-)
« Ultima modifica: 27 Maggio 2013, 19:39:40 CEST da prezzemolo86, Reason: Merged DoublePost »