2012-12-31 16 views
16

Sto lavorando a un'applicazione gamebook che mostra 12 visualizzazioni in un ViewPager. Questo è il mio PagerAdapter personalizzato:Android setBackgroundResource causa memoria insufficiente

private class ImagePagerAdapter extends PagerAdapter { 

    private int[] mImages = new int[] { R.drawable.copertinai, 
      R.drawable.blui, R.drawable.azzurroi, R.drawable.rossoi, 
      R.drawable.gialloi, R.drawable.verdei, R.drawable.rosai, 
      R.drawable.grigioi, R.drawable.neroi, R.drawable.arancionei, 
      R.drawable.marronei, R.drawable.violai, R.drawable.ulm }; 

    @Override 
    public int getCount() { 
     return mImages.length; 
    } 

    @Override 
    public boolean isViewFromObject(View view, Object object) { 
     return view == ((RelativeLayout) object); 
    } 

    @Override 
    public Object instantiateItem(ViewGroup container, int position) { 
     Context context = MainActivity.this; 
     RelativeLayout relLayImageView = new RelativeLayout(context); 
     relLayImageView.setBackgroundResource(mImages[position]); 

     ((ViewPager) container).addView(relLayImageView, new LayoutParams(
       LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 
     return relLayImageView; 
    } 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
     ((ViewPager) container).removeView((RelativeLayout) object); 
     object=null; 
     System.gc(); 
    } 
} 

In alcuni dispositivi che causano un fuori exceptionr memoria in modo casuale quando questa riga di codice si chiama

relLayImageView.setBackgroundResource(mImages[position]); 

Ma in tutti i dispositivi che vedo qualcosa di simile nel logcat pagine quando accendo:

12-31 00:25:31.655: I/dalvikvm-heap(9767): Grow heap (frag case) to 50.875MB for 10384016-byte allocation 

l'applicazione si blocca anche in alcuni dispositivi per lo stesso problema quando in un'altra attività ho impostato diversa risorsa di sfondo al layout principale basato sull'azione dell'utente. Ecco il codice:

  btn.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 


       colorButtons.get(indiceColoreAttuale).setBackgroundResource(
           unSelectedColorsRes[indiceColoreAttuale]); 

       switch (index) { 
       case 0: 
        mainLayout.setBackgroundResource(R.drawable.blus); 
        break; 
       case 1: 
        mainLayout 
          .setBackgroundResource(R.drawable.azzurros); 
        break; 
       case 2: 
        mainLayout 
          .setBackgroundResource(R.drawable.rossos); 
        break; 
       case 3: 
        mainLayout 
          .setBackgroundResource(R.drawable.giallos); 
        break; 
       case 4: 
        mainLayout 
          .setBackgroundResource(R.drawable.verdes); 
        break; 
       case 5: 
        mainLayout 
          .setBackgroundResource(R.drawable.rosas); 
        break; 
       case 6:      
        mainLayout 
          .setBackgroundResource(R.drawable.grigios); 
        break; 
       case 7: 
        mainLayout 
          .setBackgroundResource(R.drawable.neros); 
        break; 
       case 8: 
        mainLayout 
          .setBackgroundResource(R.drawable.arancios); 
        break; 
       case 9: 
        mainLayout 
          .setBackgroundResource(R.drawable.marrones); 
        break; 
       case 10: 
        mainLayout 
          .setBackgroundResource(R.drawable.violas); 
        break; 
       } 

       mainLayout.startAnimation(animationShowTextColor); 
       mainLayout.setGravity(Gravity.CENTER_HORIZONTAL); 
       indiceColoreAttuale = index; 
       colorButtons.get(index).setBackgroundResource(
         selectedColorsRes[index]); 

      } 
     }); 

Corre excepiton di nuovo quando chiamo setBackgroundResource() su mainLayout.

Spero che tu possa aiutarmi a risolvere questo, grazie in anticipo!

+0

Sembra che tu stia caricando alcuni sfondi _huge_ e che il dispositivo non abbia memoria sufficiente per loro ... –

+0

Sì, ma a volte accade su dispositivi con molta memoria, e non succede in dispositivi con meno memoria .. I caricare immagini che non sono molto grandi (da 50 a 200 kb). – TheModularMind

+0

Non suonano _huge_. Potresti provare a "riciclare" le bitmap prima di cambiare la risorsa di sfondo. Prendi il vecchio sfondo disegnabile e dopo averlo modificato vedi se è un 'BitmapDrawable', se è quindi chiama' recycle() 'sul suo' Bitmap'. –

risposta

57

Ho risolto! Tutti i tuoi suggerimenti erano buoni ma il vero problema era la cartella "/ drawable"! Ho avuto tutte le immagini nella cartella generica "/ drawable" che è considerata dal sistema come "/ drawable/mdpi", quindi quando stavo correndo in dispositivi con hdpi o più le immagini sono state ridimensionate, e sono diventate troppo grandi che causano OutOfMemoryException!

Ora sto usando "/ drawable-nodpi" per memorizzare le mie immagini. Questa cartella funziona come "/ drawable" ma le immagini non vengono mai ridimensionate!

+1

Penso che tu intenda 'drawable-nodpi' –

+0

Grazie, funziona come un fascino! – ElDoRado1239

+0

Ho notato un calo significativo nell'utilizzo della memoria. C'è qualche inconveniente a questa soluzione? –

8

Ogni applicazione Android ha memoria limitata (heap) che può essere utilizzata da Dalvik VM. È 32 MB su alcuni dispositivi è 64 MB. Quando si imposta la risorsa di sfondo, si carica tale risorsa nell'heap. Quella risorsa viene caricata come Bitmap - la sua dimensione è larghezza * altezza * dimensione pixel. Usualy Bitmap vengono caricati come immagini ARGB che ha 4 byte per pixel. Significa che il caricamento dell'immagine 1024x768 richiede 1024 * 768 * 4 = 3145728 B = 3072 kB = 3 MB su heap. Quando carichi molte immagini di grandi dimensioni, consuma tutta la memoria heap libera e causa un'eccezione di memoria insufficiente.

Per risolvere questo problema è meglio caricare le immagini il più piccolo possibile - quando si visualizza la miniatura dell'immagine è sufficiente caricarla in risoluzione che non è molto più grande della risoluzione della parte in calcestruzzo del display. Significa che quando si visualizza l'immagine su display 800x600 non è sufficiente caricare l'immagine 1024x768. Puoi usare BitmapFactory per caricare l'immagine con una risoluzione più piccola.

Metodo di utilizzo decodeResource (activity.getResources(), R.drawable.imageId, opts). BitmapFactory.Opzioni opts ha il parametro inSampleSize in cui è possibile impostare un sottocampionamento dell'immagine. Anche il parametro inPreferredConfig può essere utilizzato per impostare RGB_565 anziché ARGB_8888 nel caso in cui non sia necessaria la trasparenza.

+0

Grazie amico per queste informazioni. –

Problemi correlati