Het laden van grote afbeeldingen in Android en het vermijden van de out of memory error?

Ik ben bezig met een app die gebruik maakt van grote afbeeldingen (1390 × 870 : 150kb – 50kb). Ik ben het toevoegen van afbeeldingen als ik op een trekker/Afbeeldingpagina.

Op een bepaald moment krijg ik een out of memory error:

java.lang.OutOfMemoryError
E/AndroidRuntime(23369): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
E/AndroidRuntime(23369): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:613)
E/AndroidRuntime(23369): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:378)

Om het formaat van het beeld dat ik dit doe:

Bitmap productIndex = null;
final String imageLoc = IMAGE_LOCATION;
InputStream imageStream;
try {
     imageStream = new FileInputStream(imageLoc);
     productIndex = decodeSampledBitmapFromResource(getResources(), imageLoc, 400, 400);

     productIV.setImageBitmap(productIndex);
     } catch (FileNotFoundException e1) {
          //TODO Auto-generated catch block
          e1.printStackTrace();
     }
}


public static Bitmap decodeSampledBitmapFromResource(Resources res, String resId, int reqWidth, int reqHeight) {

//First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(resId, options);

//Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

//Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(resId, options);
}

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
//Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

    final int halfHeight = height / 3;
    final int halfWidth = width / 3;

    //Calculate the largest inSampleSize value that is a power of 2 and keeps both
    //height and width larger than the requested height and width.
    while ((halfHeight / inSampleSize) > reqHeight
            && (halfWidth / inSampleSize) > reqWidth) {
        inSampleSize *= 2;
    }
}

return inSampleSize;
}

Ik heb deze manier van formaat om ruimte te besparen in de Android Documenten:
Het Laden Van Grote Bitmaps Efficiënt

Volgens het logboek, dit is de boosdoener in de decodeSampledBitmapFromResource methode :

return BitmapFactory.decodeFile(resId, options);

—– bewerken —–
Hier is hoe ik ben het toevoegen van elk item aan de FrameLayout.

for(int ps=0;ps<productSplit.size();ps++){
    //split each product by the equals sign
    List<String> productItem = Arrays.asList(productSplit.get(ps).split("="));

    String tempCarID = productItem.get(0);
    tempCarID = tempCarID.replace(" ", "");
    if(String.valueOf(carID).equals(tempCarID)){

        ImageView productIV = new ImageView(Configurator.this);
        LayoutParams productParams = new LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        productIV.setId(Integer.parseInt(partIdsList.get(x)));
        productIV.setLayoutParams(productParams);

        final String imageLoc = productItem.get(2);

        InputStream imageStream;
        try {
            imageStream = new FileInputStream(imageLoc);
            productIndex = decodeSampledBitmapFromResource(getResources(), imageLoc, 400, 400);
            productIV.setImageBitmap(productIndex);
        } catch (FileNotFoundException e1) {
            //TODO Auto-generated catch block
            e1.printStackTrace();
        }

        productLayers.addView(productIV);

    }
}
  • Als je eenmaal hebt geladen van een bemonsterd bitmap, heb je ooit het verwijderen van uw Oog/Adapter wanneer het niet meer zichtbaar is?
  • het is altijd zichtbaar. Ik ben het draaien van een lus om items toe te voegen aan een FramedLayout. Ik update mijn vraag om dit aan te tonen.
  • Ik heb bijgewerkt de vraag. Als ik het recyclen van de productIndex Bitmap omdat het vernietigt de afbeelding en niet in mijn FrameLayout meer.
  • Maar visueel wat betekent dit, bent u overlappende bitmaps (die kan worden verspillende)? Hoeveel bitmaps u laden?
  • Ja, ik heb om een overlay van de bitmaps. Deze lagen afbeeldingen te maken van een solide beeld dat de gebruiker verzonden worden naar zichzelf of anderen. De gebruiker kan toevoegen zoveel als nodig is…
  • Is dit de moeite waard op zoek naar: Caching Bitmaps
  • Ik waardeer jullie die delen in de code van uw inspanningen, het was erg handig als ik geconfronteerd met hetzelfde probleem, maar heb niet alle code heb ik daar voor nodig is.. calculateInSampleSize() in het bijzonder. Bedankt!

InformationsquelleAutor dcp3450 | 2014-01-27

 

6 Replies
  1. 30

    Kunt u een bitmap-config om sterk verminderen van de grootte van de afbeeldingen. De standaard RGB-config ARGB8888 wat betekent vier 8-bits kanalen worden gebruikt (rood, groen, blauw, alhpa). Alpha is de transparantie van de bitmap. Deze occupy-veel geheugen – afmetingen X 4. Dus als de afm is een 4 megapixel 16 megabytes zal direct worden toegewezen op de heap – snel vermoeiend het geheugen.

    In plaats daarvan gebruik RGB_565 die tot op zekere hoogte een achteruitgang van de kwaliteit – maar om dit te compenseren, kunt u dithering de beelden.

    So – methode decodeSampledBitmapFromResource – voeg de volgende fragmenten:

     options.inPreferredConfig = Config.RGB_565;
     options.inDither = true;

    In je code:

     public static Bitmap decodeSampledBitmapFromResource(Resources res, String resId, int    reqWidth, int reqHeight) {
    
     //First decode with inJustDecodeBounds=true to check dimensions
     final BitmapFactory.Options options = new BitmapFactory.Options();
     options.inJustDecodeBounds = true;
     BitmapFactory.decodeFile(resId, options);
    
     //Calculate inSampleSize
     options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    
     //Decode bitmap with inSampleSize set
     options.inJustDecodeBounds = false;
     options.inPreferredConfig = Config.RGB_565;
     options.inDither = true;
     return BitmapFactory.decodeFile(resId, options);
     }

    Referenties:

    http://developer.android.com/reference/android/graphics/Bitmap.Config.html#ARGB_8888

    • wat voordeel heeft de instelling inSampleSize hebben?
    • BitmapFactory.Opties.inDither is afgeschaft in Android-N, u weet dat sommigen een alternatief?
    • Ik wou dat ik zou kunnen antwoorden dat. Ik ben een beetje verbaasd van de vlag is verouderd. Ik zal kijken in dit meer, in de loop van de tijd
  2. 25

    Hoge resolutie apparaten zoals S4 meestal onvoldoende geheugen als u geen afbeelding in de juiste map die is drawable-xxhdpi. U kunt ook uw afbeelding in drawable-nodpi. De reden zou uitvoeren memorey als uw afbeelding in drawable dat de android zou de schaal van de afbeelding te denken dat het beeld werd ontworpen voor een lage resolutie.

    • de beelden die gebruikt worden gedownload via een API en opgeslagen in het apparaat, sd opslag
    • Het is nog steeds mogelijk dat ze aan toe zijn aangepast voor high res, misschien kan je graven in die richting, zal ik het onderzoek zo goed en laat je weten wat ik
    • zo ver als het beeld zelf: zij zijn 72 dpi en gecomprimeerd via photoshop met “exporteren voor het web en apparaten”. De iOS-en Android-app die beide gebruik maken van dezelfde API en Afbeeldingen. De reden om afbeeldingen te groot is om rekening te houden voor het Netvlies.
    • Is dit de moeite waard op zoek naar: Caching Bitmaps
    • Jullie hoeft niet te kijken als je niet denkt dat dit het probleem is, maar ik ga het onderzoek. In mijn ervaring elke keer als ik had oom in verband met de afbeeldingen was het probleem dat ik hierboven beschreven
    • I ‘ l kijk in de link die je geplaatst nadat ik onderzoek res probleem.
    • Opgeslagen mij ook. Beste oplossing! moeten worden geaccepteerd antwoord.
    • Ik was geschokt om te ontdekken dat je juist die drawable wordt behandeld als ware het drawable-mdpi, en afbeeldingen worden geschaald door de telefoon dichtheid. Raadselachtige besluit van Android-ontwerpers, maar is wel essentieel om te weten!

  3. 2

    Here is how I'm adding each item to the FrameLayout
    dat is het probleem, de code blijven toevoegen en het toevoegen van meer foto ‘ s, en het maakt niet uit hoe goed u de grootte of hoeveel geheugen in het apparaat hebben, op zeker moment ZAL het geheugen worden uitgevoerd. Dat komt omdat elke afbeelding die u toevoegt blijft in het geheugen.

    Voor dit soort situatie wat de apps die gebruik maken van een ViewGroup dat kan recyclen uitzicht. Ik weet niet van uw lay-out, maar meestal is een ListView, GridView of een ViewPager, door recycling uitzicht u opnieuw gebruik maken van de lay-out en het kan beschikken re-afbeeldingen laden als dat nodig is.

    Voor het specifieke doel van het laden en de grootte van afbeeldingen die ik raden het gebruik van Picasso bibliotheek want het is ZEER goed geschreven, eenvoudig te gebruiken en stabiel.

    • Ja, dat is wat ik dacht dat er gebeurde. Kortom, ik heb een layout met reeksen van beelden (allemaal van hetzelfde formaat) die moeten lag op de top van elkaar. Voor elk beeld dat ik maak gebruik van een Afbeeldingpagina. Ik dacht over het houden van een ArrayList van al mijn afbeelding locaties en elke keer een nieuwe laag wordt toegevoegd afvlakken alle lagen in een bitmap-afbeelding in plaats van het toevoegen van nieuwe lagen voor elke afbeelding.
    • dat zou waarschijnlijk het werk. Maar als u alleen het toevoegen van hen, het zal altijd onvoldoende geheugen.
  4. 0

    Je nog steeds behoefte aan het beheren van de bitmap in het geheugen als ik niet zou proberen om het toewijzen van een totale ruimte van meer dan 3x de grootte van het scherm (als u denkt over het zinvol voor de scroll-gedrag). Als u een overlaging van het ene beeld op het andere, op een bepaald punt, je bent het raken van een Out of Memory error. U kan nodig zijn om te kijken naar het vastleggen van het voorafgaande beeld op het scherm als een enkele achtergrond afbeelding om te zorgen dat u nog steeds passen binnen het beschikbare geheugen. Of wanneer u een nieuw beeld overlapt met een bestaande afbeelding alleen laden en renderen van het zichtbare gedeelte. Als de prestaties wordt een probleem, dan moet je misschien overwegen OpenGL Texturen, maar de toewijzing van geheugen probleem is nog steeds hetzelfde.

    Doen gaan door alle van de Weergeven Bitmaps Training als het geeft je een aantal extra ideeën van hoe te handelen display.

    • Ik dacht na over het nemen van een “huidige status” van de FrameLayout -> afvlakken van de Bitmaps in een beeld -> het vervangen van de huidige weergave. Het platte beeld zou krijgen groter hoewel. maar ik zou niet alleen het stapelen van lagen, zoals ik nu ben. Klinkt dat niet meer goed te doen of is het ongeveer hetzelfde?
    • Het klinkt als wat ik voorstelde, zou ik nog steeds in gedachten houden dat je niet van een willekeurige grote bitmap geheugen budget. Als de achtergrond is schuifbaar, dan heb je tot nog meer games spelen om het te houden binnen het budget of het wijzigen van de grenzen van de app.
    • Niets is schuifbaar. Uiteindelijk ben ik te druk dat dit een API dus ik zal moeten afvlakken het hoe dan ook.
    • Dan op de meeste van uw achtergrond afbeelding er één is van de grootte van het scherm groot en je zult goed onder 3x alles wat anders is gelost.
    • Dus, op basis van deze opmerkingen klinkt dit beter: laden basis lagen in ArrayList -> Plat lagen -> plaats in lay-out als een bitmap… gebruiker voegt laag: voeg nieuwe laag toe ArrayList -> verwijder de huidige bitmap -> Plat lagen weer -> nieuwe bitmap in lay-out. Vervang gewoon de bitmap gebied met een voortgangsbalk als het vlakt de afbeelding.
    • Alleen u kunt bepalen of het voor jou werkt, dat wil zeggen een undo-functie een vereiste is, is het afvlakken en caching van de nieuwe achtergrond afbeelding te lang duren, en andere voorwaarden die hier niet vermeld. Als eerste stap al zou ik het proberen.

  5. 0

    Gebruik maken van Fresco bibliotheek om grote beelden zal deze fout te voorkomen.
    in xml-indeling

    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/my_image_view"
        android:layout_width="1300dp"
        android:layout_height="1300dp"
        fresco:placeholderImage="@drawable/my_drawable"
      />

    en in javacode

    Uri uri = Uri.parse("https://image.png");
    SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);
    draweeView.setImageURI(uri);

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *