2012-12-31 14 views
16

Ich arbeite an einer Gamebook-Anwendung, die 12 Ansichten in einem ViewPager zeigt. Dies ist meine Gewohnheit PagerAdapter:Android setBackgroundResource Ursache nicht genügend Speicher excepiton

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

Bei einigen Geräten es nicht genügend Arbeitsspeicher exceptionr zufällig verursachen, wenn diese Codezeile

genannt wird
relLayImageView.setBackgroundResource(mImages[position]); 

Aber in allen Geräten ich so etwas wie dies in der zu sehen logcat wenn ich umblättern:

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

die App auch in einigen Geräten für das gleiche Problem stürzen ab, wenn in einer anderen Aktivität I unterschiedliche Hintergrund Ressource festgelegt zum Hauptlayout basierend auf Benutzeraktion. Hier ist der Code:

  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]); 

      } 
     }); 

Es läuft excepiton wieder, wenn ich rufe setBackgroundResource() auf mainLayout.

Ich hoffe, Sie können mir helfen, dies zu lösen, danke im Voraus!

+0

Klingt, als würden Sie einige _huge_ Hintergründe laden und das Gerät hat nicht genug Speicher für sie ... –

+0

Ja, aber manchmal passiert auf Geräten mit viel Speicher, und passiert nicht in Geräten mit weniger Speicher .. Ich Lade Bilder, die nicht wirklich groß sind (von 50 bis 200 kb). – TheModularMind

+0

Sie klingen _huge_ nicht. Sie könnten versuchen, die Bitmaps selbst zu recyceln, bevor Sie die Hintergrundressource ändern. Holen Sie sich den alten Hintergrund aus und nach dem Ändern sehen Sie, ob es ein 'BitmapDrawable' ist, wenn es dann' recycle() 'auf seiner' Bitmap' genannt wird. –

Antwort

57

Ich habe gelöst! Alle deine Tipps waren gut, aber das eigentliche Problem war der Ordner "/ Drawable"! Ich hatte alle Bilder im "/ drawable" generischen Ordner, der vom System als "/ drawable/mdpi" betrachtet wird, also wenn ich in Geräten mit hdpi oder mehr lief, wurden die Bilder in der Größe verändert und wurden zu groß, was OutOfMemoryException verursachte!

Jetzt verwende ich "/ Drawable-Nodpi", um meine Bilder zu speichern. Dieser Ordner funktioniert wie "/ Drawable", aber die Bilder werden nie in der Größe verändert!

+1

Ich denke du meinst 'Drawable-Nodpi' –

+0

Danke, funktioniert wie ein Charme! – ElDoRado1239

+0

Ich bemerkte einen signifikanten Rückgang der Speichernutzung. Gibt es Nachteile bei dieser Lösung? –

8

Jede Android-Anwendung hat einen begrenzten Speicher (Heap), der von Dalvik VM verwendet werden kann. Es ist 32 MB auf einigen Geräten ist es 64 MB. Wenn Sie Hintergrundressource festlegen, laden Sie diese Ressource auf Heap. Diese Ressource wird als Bitmap geladen - ihre Größe ist Breite * Höhe * Pixelgröße. Üblicherweise werden Bitmaps als ARGB-Bilder geladen, die 4 Bytes pro Pixel haben. Dies bedeutet, dass das Laden von 1024x768-Bildern 1024 * 768 * 4 = 3145728 B = 3072 kB = 3 MB auf Heap dauert. Wenn Sie viele große Bilder laden, verbraucht es den gesamten freien Heap-Speicher und führt zu einer Speicherausnahme.

Um dies zu beheben, ist es besser, Bilder so klein wie möglich zu laden - wenn Sie Miniaturansicht des Bildes anzeigen, ist es ausreichend, es in einer Auflösung zu laden, die nicht viel größer ist als die Auflösung des konkreten Teils des Displays. Das heißt, wenn Sie Ihr Bild auf einem 800x600 Display anzeigen, ist es nicht ausreichend, ein 1024x768 Bild zu laden. Sie können BitmapFactory verwenden, um ein Bild in einer kleineren Auflösung zu laden.

Verwenden Sie die Methode decodeResource (activity.getResources(), R.drawable.imageId, opts). BitmapFactory.Options opts hat Parameter inSampleSize, wo Sie Subsampling des Bildes festlegen können. Mit dem Parameter inPreferredConfig kann RGB_565 anstelle von ARGB_8888 gesetzt werden, wenn Sie keine Transparenz benötigen.

+0

Vielen Dank für diese Informationen. –

Verwandte Themen