Strange z problému paměti při načítání obrazu k objektu Bitmap

hlasů
1k

Mám zobrazení seznamu s několika obrazových tlačítek na každém řádku. Když klepnete na řádek seznamu, uvádí na trh novou aktivitu. Měl jsem stavět své vlastní záložky z důvodu problému s rozvržením kamery. Činnost, která dostane zahájen výsledek je mapa. Kdybych klikněte na mé tlačítko pro spuštění náhledu obrazu (načtení obrázku z SD karty), vrátí aplikace z činnosti zpět do listviewčinnosti se psovoda výsledek, aby znovu zahájila svou novou aktivitu, která je nic víc než obraz widget.

Náhled obrázku k zobrazení seznamu se děje s kurzorem a ListAdapter. To dělá to docela jednoduché, ale nejsem si jistý, jak mohu dát změněné kopie (tj Menší bit velikosti ne pixel jako srcna tlačítku obrazu v reálném čase. Tak jsem změněna snímek, který sjel z telefonu fotoaparát.

Problém je, že jsem si chybu nedostatku paměti, když se pokusí vrátit zpět a znovu spustit 2. aktivitu.

  • Existuje způsob, jak mohu postavit adaptér seznamu snadno řádek po řádku, kde mohu změnit velikost za běhu ( bitech )?

To by bylo vhodnější, jak jsem také potřeba provést některé změny vlastností widgety / prvků v každé řadě, jak jsem schopen vybrat řádek s dotykovým displejem, protože vydání ostření. ( Mohu použít pro rollery. )

  • Vím, že mohu dělat mimo pásmo změny velikosti a zachránit mého obrazu, ale to není opravdu to, co chci dělat, ale některé ukázkový kód pro to by bylo pěkné.

Jakmile jsem zakázal obraz na zobrazení seznamu fungovalo to dobře znovu.

FYI: Takhle to dělám:

String[] from = new String[] { DBHelper.KEY_BUSINESSNAME,DBHelper.KEY_ADDRESS,DBHelper.KEY_CITY,DBHelper.KEY_GPSLONG,DBHelper.KEY_GPSLAT,DBHelper.KEY_IMAGEFILENAME  + };
int[] to = new int[] {R.id.businessname,R.id.address,R.id.city,R.id.gpslong,R.id.gpslat,R.id.imagefilename };
notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);

Tam, kde R.id.imagefilenameje ButtonImage.

Tady je můj Logcat:

01-25 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process.
01-25 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes
01-25 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.resolveUri(ImageView.java:484)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.setImageURI(ImageView.java:281)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.CursorAdapter.getView(CursorAdapter.java:150)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.obtainView(AbsListView.java:1057)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.makeAndAddView(ListView.java:1616)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.fillSpecific(ListView.java:1177)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.layoutChildren(ListView.java:1454)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.onLayout(AbsListView.java:937)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:922)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:920)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.performTraversals(ViewRoot.java:771)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Handler.dispatchMessage(Handler.java:88)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Looper.loop(Looper.java:123)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.app.ActivityThread.main(ActivityThread.java:3742)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invokeNative(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invoke(Method.java:515)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at dalvik.system.NativeStart.main(Native Method)
01-25 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed 

Mám také nový chybu při zobrazování obrazu:

01-25 22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
01-25 22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri: 
01-25 22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
01-25 22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
01-25 22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed
Položena 25/01/2009 v 12:23
zdroj uživatelem
V jiných jazycích...                            


43 odpovědí

hlasů
849

Opravit OutOfMemory chybu, měli byste udělat něco takového:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap = BitmapFactory.decodeStream(is, null, options);

Tato inSampleSizemožnost snižuje spotřebu paměti.

Zde je kompletní metodou. Za prvé to čte velikost obrazu bez dekódování samotný obsah. Pak se najde nejlepší inSampleSizehodnotu, by mělo být mocninou 2, a nakonec se obraz dekóduje.

// Decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f), null, o);

        // The new size we want to scale to
        final int REQUIRED_SIZE=70;

        // Find the correct scale value. It should be the power of 2.
        int scale = 1;
        while(o.outWidth / scale / 2 >= REQUIRED_SIZE && 
              o.outHeight / scale / 2 >= REQUIRED_SIZE) {
            scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {}
    return null;
}
Odpovězeno 05/05/2009 v 10:00
zdroj uživatelem

hlasů
543

Android Training class, „ Zobrazení rastry efektivně “, nabízí některé skvělé informace pro pochopení a jednání s výjimkou java.lang.OutOfMemoryError: bitmap size exceeds VM budgetpři načítání bitmapy.


Číst Bitmap Rozměry a typ

BitmapFactoryTřída poskytuje několik dekódování metody ( decodeByteArray(), decodeFile(), decodeResource(), atd) pro vytvoření Bitmapz různých zdrojů. Zvolit nejvhodnější metodu dekódování založené na zdroj dat obrazu. Tyto metody se pokusí přidělit paměť pro početně bitmapy a proto může snadno dojít k OutOfMemoryvýjimky. Každý typ způsobu dekódování má další podpisy, které umožňují určit volby dekódování přes BitmapFactory.Optionstřídu. Nastavením inJustDecodeBoundsvlastnost true, zatímco dekódování vyhýbá přidělení paměti, vracející se nullna bitmapový objekt, ale nastavení outWidth, outHeighta outMimeType. Tato technika umožňuje číst rozměry a typ obrazových dat před výstavbě (a přidělování paměti) bitmapy.

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

Aby se zabránilo java.lang.OutOfMemoryvýjimky, zkontrolujte rozměry bitmapu před dekódování, pokud jste naprosto důvěřujete zdroji, aby vám poskytl předvídatelně velikosti obrazových dat, který pohodlně vejde do dostupné paměti.


Načíst zmenšená verze do paměti

Nyní, že rozměry obrázku jsou známé, že mohou být použity k rozhodnutí, zda úplný obraz by měl být zaveden do paměti, nebo v případě, že podvzorkovanou verze by měla být vložen místo. Zde jsou některé faktory, aby zvážila:

  • Odhaduje se využití paměti načtení celého obrazu do paměti.
  • Velikost paměti, kterou jste ochotni se zavázat k vložení tohoto obrázku uveden jakékoliv jiné požadavky na paměť z vaší aplikace.
  • Rozměry cílové ImageView nebo UI komponenty, že obraz má být vložen do.
  • velikost obrazovky a hustota aktuálního zařízení.

Například, to nestojí za načítání obrazových bodů obrazu 1024x768 do paměti, pokud to bude nakonec být zobrazeny v 128x96 pixelů miniatury v prostředí s ImageView.

Sdělit dekodér dílčího obrazu, načítání menší verze do paměti nastaven inSampleSizena truev BitmapFactory.Optionsobjektu. Například obraz s rozlišením 2048x1536, který je dekódován s inSampleSize4 vytváří rastr cca 512x384. Vkládání to do paměti používá 0.75MB spíše než 12MB pro celý obraz (za předpokladu, konfiguraci mapy bitů ARGB_8888). Zde je metoda pro výpočet hodnota velikosti vzorku, který je síla dva založen na cílovém šířky a výšky:

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 / 2;
        final int halfWidth = width / 2;

        // 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;
}

Poznámka : příkon nejméně dvě hodnoty se počítá, protože dekodér používá závěrečnou hodnotu zaokrouhlení dolů na nejbližší mocninu dvou, dle inSampleSizedokumentace.

Chcete-li použít tuto metodu, nejprve dekódování s inJustDecodeBoundsnastaveným na true, projít volby až do konce a pak znovu dekódovat pomocí nové inSampleSizehodnoty a inJustDecodeBoundsnastaven na hodnotu false:

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

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

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

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

Tato metoda usnadňuje načtení rastrového obrázku libovolně velké velikosti do ImageViewkteré zobrazuje 100x100 pixelů miniaturu si, jak je uvedeno v následujícím příkladu kódu:

mImageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

Můžete sledovat podobný proces dekódování bitmap z jiných zdrojů, nahrazením vhodného BitmapFactory.decode*způsobu, jak je potřeba.

Odpovězeno 12/04/2012 v 17:31
zdroj uživatelem

hlasů
351

Udělal jsem malý vylepšení Fedora je kód. Je to v podstatě dělá to samé, ale bez (podle mého názoru) ošklivý while, a to vždy za následek mocninu dvou. Sláva Fedor pro výrobu originální řešení, byl jsem uvízl, dokud jsem zjistil, že jeho, a pak jsem byl schopný dělat to jeden :)

 private Bitmap decodeFile(File f){
    Bitmap b = null;

        //Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;

    FileInputStream fis = new FileInputStream(f);
    BitmapFactory.decodeStream(fis, null, o);
    fis.close();

    int scale = 1;
    if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
        scale = (int)Math.pow(2, (int) Math.ceil(Math.log(IMAGE_MAX_SIZE / 
           (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
    }

    //Decode with inSampleSize
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize = scale;
    fis = new FileInputStream(f);
    b = BitmapFactory.decodeStream(fis, null, o2);
    fis.close();

    return b;
}
Odpovězeno 23/08/2010 v 16:25
zdroj uživatelem

hlasů
220

Pocházím z iOS zkušenosti a byl jsem frustrovaný objevit problém s něčím tak základního jako nakládku a zobrazování obrazu. Koneckonců, každý, kdo má tento problém se snaží zobrazovat dostatečně velké obrázky. Každopádně, tady jsou dvě změny, které pevné můj problém (a dělal můj app velmi citlivý).

1) Pokaždé, když uděláte BitmapFactory.decodeXYZ(), ujistěte se, že projít v BitmapFactory.Optionss inPurgeablenastaveným na true(a pokud možno se inInputShareabletaké nastavena na hodnotu true).

2) nikdy použít Bitmap.createBitmap(width, height, Config.ARGB_8888). Myslím NIKDY! Nikdy jsem tu věc nebude zvyšovat chybu paměti po několika průchodech. Žádné množství recycle(), System.gc()bez ohledu pomohl. Vždy zvýšil výjimku. Ten druhý způsob, který skutečně funguje, je mít fiktivní obraz ve vašich obrazovkami (nebo jiný Bitmap, který dekóduje pomocí kroku 1 výše), změnit měřítko, aby se co chcete, pak manipulovat s výslednou bitmapu (například předáním na plátně pro více zábavy). Takže, co byste měli použít namísto zní: Bitmap.createScaledBitmap(srcBitmap, width, height, false). Pokud z jakéhokoliv důvodu musíte použít hrubou sílu vytvořit metodu, tedy alespoň projít Config.ARGB_4444.

To je téměř zaručeno, že vám ušetří hodiny, ne-li dnů. Vše, co mluví o škálování obrazu, atd. Není opravdu fungovat (pokud jste zvážit získání špatnou velikost, nebo se zhoršenými podmínkami na disk roztoku).

Odpovězeno 15/12/2011 v 23:52
zdroj uživatelem

hlasů
84

Je to známá chyba , není to proto, že z velkých souborů. Vzhledem k tomu, Android ukládá obrazovkami, že to bude z paměti po použití několika snímků. Ale já jsem našel alternativní cestu pro to, přeskočením android výchozí mezipaměti systému.

Řešení : Přesun snímků do složky „aktiva“ a použijte následující funkci získat BitmapDrawable:

public static Drawable getAssetImage(Context context, String filename) throws IOException {
    AssetManager assets = context.getResources().getAssets();
    InputStream buffer = new BufferedInputStream((assets.open("drawable/" + filename + ".png")));
    Bitmap bitmap = BitmapFactory.decodeStream(buffer);
    return new BitmapDrawable(context.getResources(), bitmap);
}
Odpovězeno 24/05/2011 v 21:17
zdroj uživatelem

hlasů
69

Měl jsem stejný problém a vyřešil tím, že odstraní funkce BitmapFactory.decodeStream nebo decodeFile a místo toho použil BitmapFactory.decodeFileDescriptor

decodeFileDescriptor Vypadá to, že žádá různé nativní metody než decodeStream / decodeFile.

Tak jako tak, co fungovalo byl tento (Všimněte si, že jsem přidal několik možností, jak někteří měli výše, ale to není to, co dělal rozdíl Co je důležité je volání. BitmapFactory.decodeFileDescriptor místo decodeStream nebo decodeFile ):

private void showImage(String path)   {
    Log.i("showImage","loading:"+path);
    BitmapFactory.Options bfOptions=new BitmapFactory.Options();
    bfOptions.inDither=false;                     //Disable Dithering mode
    bfOptions.inPurgeable=true;                   //Tell to gc that whether it needs free memory, the Bitmap can be cleared
    bfOptions.inInputShareable=true;              //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
    bfOptions.inTempStorage=new byte[32 * 1024]; 


    File file=new File(path);
    FileInputStream fs=null;
    try {
        fs = new FileInputStream(file);
    } catch (FileNotFoundException e) {
        //TODO do something intelligent
        e.printStackTrace();
    }

    try {
        if(fs!=null) bm=BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);
    } catch (IOException e) {
        //TODO do something intelligent
        e.printStackTrace();
    } finally{ 
        if(fs!=null) {
            try {
                fs.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    //bm=BitmapFactory.decodeFile(path, bfOptions); This one causes error: java.lang.OutOfMemoryError: bitmap size exceeds VM budget

    im.setImageBitmap(bm);
    //bm.recycle();
    bm=null;



}

Myslím, že to je problém s nativní funkce používané v decodeStream / decodeFile. I potvrdily, že jiná nativní metoda se nazývá při použití decodeFileDescriptor. Co jsem četl, je také „že Images (Bitmapy) nejsou přidělovány ve standardním Java způsobem, ale přes nativní volání, přidělené prostředky jsou prováděny mimo virtuální haldy, ale jsou počítány proti němu!

Odpovězeno 19/08/2011 v 02:55
zdroj uživatelem

hlasů
64

Myslím, že nejlepší způsob, jak se vyhnout OutOfMemoryErrorse tomu čelit a pochopit ji.

Udělal jsem aplikaci, aby záměrně vyvolávat OutOfMemoryErrora sledovat využití paměti.

Poté, co jsem udělal spoustu experimentů s touto aplikací, mám následující závěry:

Budu mluvit o SDK verze před Med různý první.

  1. Bitmapa je uloženo v nativním hromadu, ale dostane odpadky shromažďují automaticky volá recyklovat () je zbytečné.

  2. Pokud {VM velikost haldy} + {přidělené nativní haldy paměti}> = {VM omezení velikosti haldy pro zařízení}, a vy se snažíte vytvořit bitmapu, bude OOM být hozen.

    UPOZORNĚNÍ: VM HEAP SIZE se počítá spíše než VM alokovaná paměť.

  3. Velikost VM Heap nikdy za tepla po pěstovány, a to i v případě, že přidělené paměti VM je smrštitelná.

  4. Takže musíte mít vrchol VM paměti co nejníže, aby VM Heap velikosti od roste příliš velký pro uložení dostupné paměti pro bitmapy.

  5. Ruční volání System.gc () je bezvýznamný, bude systém nejprve zavolat, než se snaží pěstovat velikost haldy.

  6. Nativní Heap Velikost nikdy zmenšovat taky, ale to není započítán pro OOM, takže není třeba se starat o to.

Potom, mluvme o SDK začíná od Med různý.

  1. Bitová mapa je uložena v haldě VM, nativní paměti není počítáno pro OOM.

  2. Podmínkou pro OOM je mnohem jednodušší: {VM velikost haldy}> = {VM omezení velikosti haldy pro zařízení}.

  3. Takže máte více dostupné paměti pro vytvoření rastrového obrázku se stejným omezení velikosti haldy, OOM je méně pravděpodobné, že bude vyhozen.

Zde jsou některé z mých úvah o odvoz odpadu a nevracení paměti.

Můžete vidět sami v App. Je-li činnost uzavřela AsyncTask, který byl stále běží po aktivita byla zničena, aktivita nebude mít odpadky shromažďují do AsyncTask konce.

Je to proto, AsyncTask je instance anonymní vnitřní třídy, platí odkaz na aktivity.

Volání AsyncTask.cancel (pravou) nebude zastavily popravy, zda je úloha zablokována na operaci IO v pozadí nití.

Zpětná volání jsou anonymní vnitřní třídy taky, takže pokud statické instance v projektu je drží a že jich není uvolnění paměti by unikly.

Pokud jste naplánovali opakující se ani zpožděný úkol, například časovač, a nevolejte zrušit () a očištění () v onPause (), paměť by unikly.

Odpovězeno 01/12/2012 v 04:50
zdroj uživatelem

hlasů
58

Viděl jsem spoustu otázek o OOM výjimky a ukládání do mezipaměti v poslední době. Vodicí developer má opravdu dobrý článek na toto téma, ale některé inklinuje k selhání na jeho zavedení do vhodným způsobem.

Z tohoto důvodu jsem napsal příklad aplikace, která demonstruje ukládání do mezipaměti v Android prostředí. Tato implementace dosud nedostal k OOM.

Podívejte se na konci tohoto odpověď na odkaz ke zdrojovému kódu.

požadavky:

  • Android API 2.1 nebo vyšší (jsem prostě nedokázal získat dostupné paměti pro aplikace v API 1.6 - to je jediný kus kódu, který nefunguje v API 1.6)
  • Android podpůrný balíček

Snímek obrazovky

Funkce:

  • Zachovává cache, pokud je změna orientace pomocí Singleton
  • Použijte jednu osminu účelově aplikační paměti do vyrovnávací paměti (upravovat, pokud chcete)
  • Velké bitmapy dostane zmenšen (můžete definovat maximální obrazové body, které chcete povolit)
  • Kontroluje , že je připojení k internetu k dispozici před stažením bitmapy
  • Tím zajistíte, že jste jen konkretizaci jeden úkol za sebou
  • Pokud jste házel je ListViewpryč, to prostě nebude stahovat rastry mezi

To nezahrnuje:

  • Disk cache. To by mělo být snadné implementovat stejně - jen bod na jiný úkol, který chytne bitmapy z disku

Ukázkový kód:

Obrázky, které jsou stažené jsou obrazy (75x75) z Flickr. Nicméně, bez ohledu na dal obraz urls Chcete-li být zpracovány, a aplikace se zmenšenou pokud překročí maxima. V této aplikaci jsou URL jednoduše v Stringpoli.

LruCacheJe dobrý způsob, jak se vypořádat s rastry. Nicméně, v této žádosti jsem dal instanci LruCacheuvnitř jiného vyrovnávací třídy, které jsem vytvořil s cílem získat žádost schůdnější.

Cache.java kritický věci (dále jen loadBitmap()metoda je nejdůležitější):

public Cache(int size, int maxWidth, int maxHeight) {
    // Into the constructor you add the maximum pixels
    // that you want to allow in order to not scale images.
    mMaxWidth = maxWidth;
    mMaxHeight = maxHeight;

    mBitmapCache = new LruCache<String, Bitmap>(size) {
        protected int sizeOf(String key, Bitmap b) {
            // Assuming that one pixel contains four bytes.
            return b.getHeight() * b.getWidth() * 4;
        }
    };

    mCurrentTasks = new ArrayList<String>();    
}

/**
 * Gets a bitmap from cache. 
 * If it is not in cache, this method will:
 * 
 * 1: check if the bitmap url is currently being processed in the
 * BitmapLoaderTask and cancel if it is already in a task (a control to see
 * if it's inside the currentTasks list).
 * 
 * 2: check if an internet connection is available and continue if so.
 * 
 * 3: download the bitmap, scale the bitmap if necessary and put it into
 * the memory cache.
 * 
 * 4: Remove the bitmap url from the currentTasks list.
 * 
 * 5: Notify the ListAdapter.
 * 
 * @param mainActivity - Reference to activity object, in order to
 * call notifyDataSetChanged() on the ListAdapter.
 * @param imageKey - The bitmap url (will be the key).
 * @param imageView - The ImageView that should get an
 * available bitmap or a placeholder image.
 * @param isScrolling - If set to true, we skip executing more tasks since
 * the user probably has flinged away the view.
 */
public void loadBitmap(MainActivity mainActivity, 
        String imageKey, ImageView imageView,
        boolean isScrolling) {
    final Bitmap bitmap = getBitmapFromCache(imageKey); 

    if (bitmap != null) {
        imageView.setImageBitmap(bitmap);
    } else {
        imageView.setImageResource(R.drawable.ic_launcher);
        if (!isScrolling && !mCurrentTasks.contains(imageKey) && 
                mainActivity.internetIsAvailable()) {
            BitmapLoaderTask task = new BitmapLoaderTask(imageKey,
                    mainActivity.getAdapter());
            task.execute();
        }
    } 
}

Neměli byste třeba upravit cokoli v souboru Cache.java pokud chcete implementovat disku do mezipaměti.

MainActivity.java kritický věci:

public void onScrollStateChanged(AbsListView view, int scrollState) {
    if (view.getId() == android.R.id.list) {
        // Set scrolling to true only if the user has flinged the       
        // ListView away, hence we skip downloading a series
        // of unnecessary bitmaps that the user probably
        // just want to skip anyways. If we scroll slowly it
        // will still download bitmaps - that means
        // that the application won't wait for the user
        // to lift its finger off the screen in order to
        // download.
        if (scrollState == SCROLL_STATE_FLING) {
            mIsScrolling = true;
        } else {
            mIsScrolling = false;
            mListAdapter.notifyDataSetChanged();
        }
    } 
}

// Inside ListAdapter...
@Override
public View getView(final int position, View convertView, ViewGroup parent) {           
    View row = convertView;
    final ViewHolder holder;

    if (row == null) {
        LayoutInflater inflater = getLayoutInflater();
        row = inflater.inflate(R.layout.main_listview_row, parent, false);  
        holder = new ViewHolder(row);
        row.setTag(holder);
    } else {
        holder = (ViewHolder) row.getTag();
    }   

    final Row rowObject = getItem(position);

    // Look at the loadBitmap() method description...
    holder.mTextView.setText(rowObject.mText);      
    mCache.loadBitmap(MainActivity.this,
            rowObject.mBitmapUrl, holder.mImageView,
            mIsScrolling);  

    return row;
}

getView()volána velmi často. Je to obvykle není dobrý nápad stáhnout obrázky tam, kdybychom nezavedly šek, který nám zajistí, že nebudeme začít nekonečné množství vláken na řadě. Cache.java zkontroluje, zda rowObject.mBitmapUrluž je úkol, a pokud ano, bude to nelze spustit další. Proto jsme se s největší pravděpodobností nebude překročení omezení pracovní fronty od AsyncTaskbazénu.

Stažení:

Zde si můžete stáhnout zdrojový kód z https://www.dropbox.com/s/pvr9zyl811tfeem/ListViewImageCache.zip .


Poslední slova:

Testoval jsem to po dobu několika týdnů, jsem ještě nedostal jediný OOM výjimku. Testoval jsem to na emulátoru, na mém Nexus One a na mé Nexus S. jsem otestoval URL obrázků, které obsahují obrázky, které byly v HD kvalitě. Jedinou překážkou je, že to zabere více času ke stažení.

Je tu jen jeden z možných scénářů, kde jsem si představit, že se objeví OOM, a to pokud budeme stahovat mnoho, opravdu velké obrazy, a předtím, než se dostanou zmenšen a dát do mezipaměti, bude zároveň zabírají více paměti a způsobit OOM. Ale to není ani ideální situace stejně, a to s největší pravděpodobností nebude možné řešit ve více proveditelným způsobem.

Hlásit chyby v komentářích! :-)

Odpovězeno 24/08/2012 v 11:32
zdroj uživatelem

hlasů
36

Udělal jsem následující vzít obrázek a změnit jeho velikost v reálném čase. Snad to pomůže

Bitmap bm;
bm = Bitmap.createScaledBitmap(BitmapFactory.decodeFile(filepath), 100, 100, true);
mPicture = new ImageView(context);
mPicture.setImageBitmap(bm);    
Odpovězeno 16/02/2009 v 07:23
zdroj uživatelem

hlasů
31

Zdá se, že se jedná o velmi dlouhý běh problém, s mnoha odlišnými vysvětlení. Vzal jsem radu dvou nejčastějších prezentovaných odpovědí zde, ale ani jeden z nich vyřešili své problémy VM tvrdí, že nemůže dovolit bajtů provést dekódování část procesu. Po nějaké kopání jsem se dozvěděl, že skutečným problémem je zde dekódovací proces odebrání od NATIVE haldy.

Viz zde: BitmapFactory OOM mi zblázním

Které mě vedou k dalším diskusním vlákně, kde jsem našel několik dalších řešení tohoto problému. Jedním z nich je volání System.gc();manuálně poté, co se objeví na disk. Ale to vlastně dělá vaše aplikace používat více paměti, ve snaze snížit nativní haldy. Lepším řešením k vydání 2.0 (Donut) je použít BitmapFactory volbu „inPurgeable“. Tak jsem se prostě přidal o2.inPurgeable=true;těsně po o2.inSampleSize=scale;.

Více na toto téma zde: Je limit paměti haldy pouze 6M?

Teď, když řekl všechno, Jsem úplný hlupák s Java a Android taky. Takže pokud si myslíte, že je to hrozný způsob, jak vyřešit tento problém, máte asi pravdu. ;-) Ale tohle pracoval zázraky pro mě, a já jsem zjistil, že je možné spustit virtuální počítač z haldy mezipaměti teď. Jedinou nevýhodou se mi podaří najít, je, že jste trashing vaši mezipaměti nakreslený obrázek. Což znamená, že pokud jdete zpátky do tohoto obrazu, jste překreslení ji pokaždé. V případě, jak moje žádost funguje, to není opravdu problém. Váš se může lišit.

Odpovězeno 19/05/2011 v 17:49
zdroj uživatelem

hlasů
29

Bohužel , pokud žádná z výše uvedených funguje, pak přidat na svou Manifest souboru. Uvnitř aplikace tag

 <application
         android:largeHeap="true"
Odpovězeno 19/05/2015 v 05:51
zdroj uživatelem

hlasů
26

Použijte bitmap.recycle();To pomáhá bez jakéhokoliv problému kvality obrazu.

Odpovězeno 07/11/2010 v 12:08
zdroj uživatelem

hlasů
24

Jsem vyřešit stejný problém následujícím způsobem.

Bitmap b = null;
Drawable d;
ImageView i = new ImageView(mContext);
try {
    b = Bitmap.createBitmap(320,424,Bitmap.Config.RGB_565);
    b.eraseColor(0xFFFFFFFF);
    Rect r = new Rect(0, 0,320 , 424);
    Canvas c = new Canvas(b);
    Paint p = new Paint();
    p.setColor(0xFFC0C0C0);
    c.drawRect(r, p);
    d = mContext.getResources().getDrawable(mImageIds[position]);
    d.setBounds(r);
    d.draw(c);

    /*   
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inTempStorage = new byte[128*1024];
        b = BitmapFactory.decodeStream(mContext.getResources().openRawResource(mImageIds[position]), null, o2);
        o2.inSampleSize=16;
        o2.inPurgeable = true;
    */
} catch (Exception e) {

}
i.setImageBitmap(b);
Odpovězeno 04/06/2011 v 10:44
zdroj uživatelem

hlasů
24

Mám mnohem účinnější řešení, které nevyžaduje změnu velikosti jakéhokoli druhu. Jednoduše dekódování bitmapového pouze jednou a pak ji do mezipaměti na mapě proti svému jménu. Pak stačí načíst bitmapu proti jménu a nastavit jej do ImageView. Není nic, co je třeba udělat.

To bude fungovat, protože skutečná binární data dekódovaného bitmapy není uložen v Dalvik VM haldy. Je uložen externě. Takže pokaždé, když dekódování rastrový obrázek, přidělí paměť mimo VM hromadu, která se nikdy uvolněno GC

Které vám pomohou lépe ocenit to, představte si, že jste stále ur obrazu v protažitelné složky. Jen dostanete obraz vytvořil jsem getResources (). getDrwable (R.drawable.). Tím nejsou schopny dekódovat soubor na disk pokaždé, ale znovu použít již dekódované instanci vždy, když to říkají. Takže v podstatě je to cache.

Teď, protože disk je v souboru někde (nebo může být dokonce přichází z externího serveru), je vaší povinností mezipaměti dekódované bitmapový instance znovu použít kdekoliv je potřeba.

Snad to pomůže.

Odpovězeno 02/03/2011 v 19:17
zdroj uživatelem

hlasů
23

Tato pracoval pro mě!

public Bitmap readAssetsBitmap(String filename) throws IOException {
    try {
        BitmapFactory.Options options = new BitmapFactory.Options(); 
        options.inPurgeable = true;
        Bitmap bitmap = BitmapFactory.decodeStream(assets.open(filename), null, options);
        if(bitmap == null) {
            throw new IOException("File cannot be opened: It's value is null");
        } else {
            return bitmap;
        }
    } catch (IOException e) {
        throw new IOException("File cannot be opened: " + e.getMessage());
    }
}
Odpovězeno 09/06/2012 v 21:33
zdroj uživatelem

hlasů
23

Existují dva problémy ....

  • Bitmap paměť není v VM haldy, ale spíše v nativním haldě - viz BitmapFactory OOM mi zblázním
  • odvoz odpadu pro nativní haldy je línější než VM hromady - takže budete muset být docela agresivní o tom bitmap.recycle a bitmap = null pokaždé projít onPause nebo onDestroy určitá činnost v
Odpovězeno 12/05/2011 v 05:40
zdroj uživatelem

hlasů
19

Skvělé odpovědi tady, ale chtěl jsem si plně použitelnou třídu k vyřešení tohoto problému .. tak jsem to udělal jeden.

Tady je můj BitmapHelper třída , která je OutOfMemoryError důkazem :-)

import java.io.File;
import java.io.FileInputStream;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

public class BitmapHelper
{

    //decodes image and scales it to reduce memory consumption
    public static Bitmap decodeFile(File bitmapFile, int requiredWidth, int requiredHeight, boolean quickAndDirty)
    {
        try
        {
            //Decode image size
            BitmapFactory.Options bitmapSizeOptions = new BitmapFactory.Options();
            bitmapSizeOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, bitmapSizeOptions);

            // load image using inSampleSize adapted to required image size
            BitmapFactory.Options bitmapDecodeOptions = new BitmapFactory.Options();
            bitmapDecodeOptions.inTempStorage = new byte[16 * 1024];
            bitmapDecodeOptions.inSampleSize = computeInSampleSize(bitmapSizeOptions, requiredWidth, requiredHeight, false);
            bitmapDecodeOptions.inPurgeable = true;
            bitmapDecodeOptions.inDither = !quickAndDirty;
            bitmapDecodeOptions.inPreferredConfig = quickAndDirty ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888;

            Bitmap decodedBitmap = BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, bitmapDecodeOptions);

            // scale bitmap to mathc required size (and keep aspect ratio)

            float srcWidth = (float) bitmapDecodeOptions.outWidth;
            float srcHeight = (float) bitmapDecodeOptions.outHeight;

            float dstWidth = (float) requiredWidth;
            float dstHeight = (float) requiredHeight;

            float srcAspectRatio = srcWidth / srcHeight;
            float dstAspectRatio = dstWidth / dstHeight;

            // recycleDecodedBitmap is used to know if we must recycle intermediary 'decodedBitmap'
            // (DO NOT recycle it right away: wait for end of bitmap manipulation process to avoid
            // java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@416ee7d8
            // I do not excatly understand why, but this way it's OK

            boolean recycleDecodedBitmap = false;

            Bitmap scaledBitmap = decodedBitmap;
            if (srcAspectRatio < dstAspectRatio)
            {
                scaledBitmap = getScaledBitmap(decodedBitmap, (int) dstWidth, (int) (srcHeight * (dstWidth / srcWidth)));
                // will recycle recycleDecodedBitmap
                recycleDecodedBitmap = true;
            }
            else if (srcAspectRatio > dstAspectRatio)
            {
                scaledBitmap = getScaledBitmap(decodedBitmap, (int) (srcWidth * (dstHeight / srcHeight)), (int) dstHeight);
                recycleDecodedBitmap = true;
            }

            // crop image to match required image size

            int scaledBitmapWidth = scaledBitmap.getWidth();
            int scaledBitmapHeight = scaledBitmap.getHeight();

            Bitmap croppedBitmap = scaledBitmap;

            if (scaledBitmapWidth > requiredWidth)
            {
                int xOffset = (scaledBitmapWidth - requiredWidth) / 2;
                croppedBitmap = Bitmap.createBitmap(scaledBitmap, xOffset, 0, requiredWidth, requiredHeight);
                scaledBitmap.recycle();
            }
            else if (scaledBitmapHeight > requiredHeight)
            {
                int yOffset = (scaledBitmapHeight - requiredHeight) / 2;
                croppedBitmap = Bitmap.createBitmap(scaledBitmap, 0, yOffset, requiredWidth, requiredHeight);
                scaledBitmap.recycle();
            }

            if (recycleDecodedBitmap)
            {
                decodedBitmap.recycle();
            }
            decodedBitmap = null;

            scaledBitmap = null;
            return croppedBitmap;
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * compute powerOf2 or exact scale to be used as {@link BitmapFactory.Options#inSampleSize} value (for subSampling)
     * 
     * @param requiredWidth
     * @param requiredHeight
     * @param powerOf2
     *            weither we want a power of 2 sclae or not
     * @return
     */
    public static int computeInSampleSize(BitmapFactory.Options options, int dstWidth, int dstHeight, boolean powerOf2)
    {
        int inSampleSize = 1;

        // Raw height and width of image
        final int srcHeight = options.outHeight;
        final int srcWidth = options.outWidth;

        if (powerOf2)
        {
            //Find the correct scale value. It should be the power of 2.

            int tmpWidth = srcWidth, tmpHeight = srcHeight;
            while (true)
            {
                if (tmpWidth / 2 < dstWidth || tmpHeight / 2 < dstHeight)
                    break;
                tmpWidth /= 2;
                tmpHeight /= 2;
                inSampleSize *= 2;
            }
        }
        else
        {
            // Calculate ratios of height and width to requested height and width
            final int heightRatio = Math.round((float) srcHeight / (float) dstHeight);
            final int widthRatio = Math.round((float) srcWidth / (float) dstWidth);

            // Choose the smallest ratio as inSampleSize value, this will guarantee
            // a final image with both dimensions larger than or equal to the
            // requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }

        return inSampleSize;
    }

    public static Bitmap drawableToBitmap(Drawable drawable)
    {
        if (drawable instanceof BitmapDrawable)
        {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }

    public static Bitmap getScaledBitmap(Bitmap bitmap, int newWidth, int newHeight)
    {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;

        // CREATE A MATRIX FOR THE MANIPULATION
        Matrix matrix = new Matrix();
        // RESIZE THE BIT MAP
        matrix.postScale(scaleWidth, scaleHeight);

        // RECREATE THE NEW BITMAP
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
        return resizedBitmap;
    }

}
Odpovězeno 03/02/2013 v 16:03
zdroj uživatelem

hlasů
18

To funguje pro mě.

Bitmap myBitmap;

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.InPurgeable = true;
options.OutHeight = 50;
options.OutWidth = 50;
options.InSampleSize = 4;

File imgFile = new File(filepath);
myBitmap = BitmapFactory.DecodeFile(imgFile.AbsolutePath, options);

a to je na C # monodroid. můžete snadno změnit cestu k obrázku. co zde důležité je volby, které lze nastavit.

Odpovězeno 02/10/2012 v 11:33
zdroj uživatelem

hlasů
18

Žádná z odpovědí výše pracoval pro mě, ale já jsem přišel s strašně ošklivé řešení, které problém vyřešil. Přidal jsem velmi malé, 1x1 pixel obrazu na můj projekt jako prostředek, a naložili ho do ImageView před voláním do garbage collector. Myslím, že by to mohlo být, že ImageView nebyl uvolnění rastr, takže GC nikdy ji zvedl. Je to ošklivé, ale zdá se, že bude pracovat pro tuto chvíli.

if (bitmap != null)
{
  bitmap.recycle();
  bitmap = null;
}
if (imageView != null)
{
  imageView.setImageResource(R.drawable.tiny); // This is my 1x1 png.
}
System.gc();

imageView.setImageBitmap(...); // Do whatever you need to do to load the image you want.
Odpovězeno 07/12/2011 v 13:32
zdroj uživatelem

hlasů
14

V jednom z mé žádosti musím vyfotit buď Camera/Gallery. Pokud uživatel klikne obraz z kamery (může být 2MP, 5MP nebo 8MP), velikost obrazu se pohybuje od kBsekund až MBsekund. Pokud velikost obrazu je menší (nebo až 1-2MB) výše kódu v pořádku, ale když mám obraz o velikosti nad 4MB nebo 5 MB pak OOMpřichází v rámci :(

Potom jsem pracoval na řešení tohoto problému a nakonec jsem udělal pod vylepšení Fedor (Všechny kredity, aby Fedor pro výrobu takového řešení pěkné) kód :)

private Bitmap decodeFile(String fPath) {
    // Decode image size
    BitmapFactory.Options opts = new BitmapFactory.Options();
    /*
     * If set to true, the decoder will return null (no bitmap), but the
     * out... fields will still be set, allowing the caller to query the
     * bitmap without having to allocate the memory for its pixels.
     */
    opts.inJustDecodeBounds = true;
    opts.inDither = false; // Disable Dithering mode
    opts.inPurgeable = true; // Tell to gc that whether it needs free
                                // memory, the Bitmap can be cleared
    opts.inInputShareable = true; // Which kind of reference will be used to
                                    // recover the Bitmap data after being
                                    // clear, when it will be used in the
                                    // future

    BitmapFactory.decodeFile(fPath, opts);

    // The new size we want to scale to
    final int REQUIRED_SIZE = 70;

    // Find the correct scale value. 
    int scale = 1;

    if (opts.outHeight > REQUIRED_SIZE || opts.outWidth > REQUIRED_SIZE) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) opts.outHeight
                / (float) REQUIRED_SIZE);
        final int widthRatio = Math.round((float) opts.outWidth
                / (float) REQUIRED_SIZE);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        scale = heightRatio < widthRatio ? heightRatio : widthRatio;//
    }

    // Decode bitmap with inSampleSize set
    opts.inJustDecodeBounds = false;

    opts.inSampleSize = scale;

    Bitmap bm = BitmapFactory.decodeFile(fPath, opts).copy(
            Bitmap.Config.RGB_565, false);

    return bm;

}

Doufám, že to pomůže kamarády čelí stejnému problému!

více naleznete v tomto

Odpovězeno 06/02/2013 v 15:53
zdroj uživatelem

hlasů
14

To se jeví jako vhodné místo se podělil o své užitné třídu pro nakládání a zpracování snímků s komunitou, jste vítáni, aby jej použít a upravit jej volně.

package com.emil;

import java.io.IOException;
import java.io.InputStream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

/**
 * A class to load and process images of various sizes from input streams and file paths.
 * 
 * @author Emil http://stackoverflow.com/users/220710/emil
 *
 */
public class ImageProcessing {

    public static Bitmap getBitmap(InputStream stream, int sampleSize, Bitmap.Config bitmapConfig) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForSampling(sampleSize, bitmapConfig);
        Bitmap bm = BitmapFactory.decodeStream(stream,null,options);
        if(ImageProcessing.checkDecode(options)){
            return bm;
        }else{
            throw new IOException("Image decoding failed, using stream.");
        }
    }

    public static Bitmap getBitmap(String imgPath, int sampleSize, Bitmap.Config bitmapConfig) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForSampling(sampleSize, bitmapConfig);
        Bitmap bm = BitmapFactory.decodeFile(imgPath,options);
        if(ImageProcessing.checkDecode(options)){
            return bm;
        }else{
            throw new IOException("Image decoding failed, using file path.");
        }
    }

    public static Dimensions getDimensions(InputStream stream) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForDimensions();
        BitmapFactory.decodeStream(stream,null,options);
        if(ImageProcessing.checkDecode(options)){
            return new ImageProcessing.Dimensions(options.outWidth,options.outHeight);
        }else{
            throw new IOException("Image decoding failed, using stream.");
        }
    }

    public static Dimensions getDimensions(String imgPath) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForDimensions();
        BitmapFactory.decodeFile(imgPath,options);
        if(ImageProcessing.checkDecode(options)){
            return new ImageProcessing.Dimensions(options.outWidth,options.outHeight);
        }else{
            throw new IOException("Image decoding failed, using file path.");
        }
    }

    private static boolean checkDecode(BitmapFactory.Options options){
        // Did decode work?
        if( options.outWidth<0 || options.outHeight<0 ){
            return false;
        }else{
            return true;
        }
    }

    /**
     * Creates a Bitmap that is of the minimum dimensions necessary
     * @param bm
     * @param min
     * @return
     */
    public static Bitmap createMinimalBitmap(Bitmap bm, ImageProcessing.Minimize min){
        int newWidth, newHeight;
        switch(min.type){
        case WIDTH:
            if(bm.getWidth()>min.minWidth){
                newWidth=min.minWidth;
                newHeight=ImageProcessing.getScaledHeight(newWidth, bm);
            }else{
                // No resize
                newWidth=bm.getWidth();
                newHeight=bm.getHeight();
            }
            break;
        case HEIGHT:
            if(bm.getHeight()>min.minHeight){
                newHeight=min.minHeight;
                newWidth=ImageProcessing.getScaledWidth(newHeight, bm);
            }else{
                // No resize
                newWidth=bm.getWidth();
                newHeight=bm.getHeight();
            }
            break;
        case BOTH: // minimize to the maximum dimension
        case MAX:
            if(bm.getHeight()>bm.getWidth()){
                // Height needs to minimized
                min.minDim=min.minDim!=null ? min.minDim : min.minHeight;
                if(bm.getHeight()>min.minDim){
                    newHeight=min.minDim;
                    newWidth=ImageProcessing.getScaledWidth(newHeight, bm);
                }else{
                    // No resize
                    newWidth=bm.getWidth();
                    newHeight=bm.getHeight();
                }
            }else{
                // Width needs to be minimized
                min.minDim=min.minDim!=null ? min.minDim : min.minWidth;
                if(bm.getWidth()>min.minDim){
                    newWidth=min.minDim;
                    newHeight=ImageProcessing.getScaledHeight(newWidth, bm);
                }else{
                    // No resize
                    newWidth=bm.getWidth();
                    newHeight=bm.getHeight();
                }
            }
            break;
        default:
            // No resize
            newWidth=bm.getWidth();
            newHeight=bm.getHeight();
        }
        return Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
    }

    public static int getScaledWidth(int height, Bitmap bm){
        return (int)(((double)bm.getWidth()/bm.getHeight())*height);
    }

    public static int getScaledHeight(int width, Bitmap bm){
        return (int)(((double)bm.getHeight()/bm.getWidth())*width);
    }

    /**
     * Get the proper sample size to meet minimization restraints
     * @param dim
     * @param min
     * @param multipleOf2 for fastest processing it is recommended that the sample size be a multiple of 2
     * @return
     */
    public static int getSampleSize(ImageProcessing.Dimensions dim, ImageProcessing.Minimize min, boolean multipleOf2){
        switch(min.type){
        case WIDTH:
            return ImageProcessing.getMaxSampleSize(dim.width, min.minWidth, multipleOf2);
        case HEIGHT:
            return ImageProcessing.getMaxSampleSize(dim.height, min.minHeight, multipleOf2);
        case BOTH:
            int widthMaxSampleSize=ImageProcessing.getMaxSampleSize(dim.width, min.minWidth, multipleOf2);
            int heightMaxSampleSize=ImageProcessing.getMaxSampleSize(dim.height, min.minHeight, multipleOf2);
            // Return the smaller of the two
            if(widthMaxSampleSize<heightMaxSampleSize){
                return widthMaxSampleSize;
            }else{
                return heightMaxSampleSize;
            }
        case MAX:
            // Find the larger dimension and go bases on that
            if(dim.width>dim.height){
                return ImageProcessing.getMaxSampleSize(dim.width, min.minDim, multipleOf2);
            }else{
                return ImageProcessing.getMaxSampleSize(dim.height, min.minDim, multipleOf2);
            }
        }
        return 1;
    }

    public static int getMaxSampleSize(int dim, int min, boolean multipleOf2){
        int add=multipleOf2 ? 2 : 1;
        int size=0;
        while(min<(dim/(size+add))){
            size+=add;
        }
        size = size==0 ? 1 : size;
        return size;        
    }

    public static class Dimensions {
        int width;
        int height;

        public Dimensions(int width, int height) {
            super();
            this.width = width;
            this.height = height;
        }

        @Override
        public String toString() {
            return width+" x "+height;
        }
    }

    public static class Minimize {
        public enum Type {
            WIDTH,HEIGHT,BOTH,MAX
        }
        Integer minWidth;
        Integer minHeight;
        Integer minDim;
        Type type;

        public Minimize(int min, Type type) {
            super();
            this.type = type;
            switch(type){
            case WIDTH:
                this.minWidth=min;
                break;
            case HEIGHT:
                this.minHeight=min;
                break;
            case BOTH:
                this.minWidth=min;
                this.minHeight=min;
                break;
            case MAX:
                this.minDim=min;
                break;
            }
        }

        public Minimize(int minWidth, int minHeight) {
            super();
            this.type=Type.BOTH;
            this.minWidth = minWidth;
            this.minHeight = minHeight;
        }

    }

    /**
     * Estimates size of Bitmap in bytes depending on dimensions and Bitmap.Config
     * @param width
     * @param height
     * @param config
     * @return
     */
    public static long estimateBitmapBytes(int width, int height, Bitmap.Config config){
        long pixels=width*height;
        switch(config){
        case ALPHA_8: // 1 byte per pixel
            return pixels;
        case ARGB_4444: // 2 bytes per pixel, but depreciated
            return pixels*2;
        case ARGB_8888: // 4 bytes per pixel
            return pixels*4;
        case RGB_565: // 2 bytes per pixel
            return pixels*2;
        default:
            return pixels;
        }
    }

    private static BitmapFactory.Options getOptionsForDimensions(){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        return options;
    }

    private static BitmapFactory.Options getOptionsForSampling(int sampleSize, Bitmap.Config bitmapConfig){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        options.inDither = false;
        options.inSampleSize = sampleSize;
        options.inScaled = false;
        options.inPreferredConfig = bitmapConfig;
        return options;
    }
}
Odpovězeno 03/11/2012 v 00:41
zdroj uživatelem

hlasů
13

Jen jsem před pár minutami se dostali do této problematiky. Vyřešil jsem to tím, že dělá lepší práci při správě mé ListView adaptér. Myslel jsem, že to byl problém se stovkami 50x50px obrázků jsem používal, Ukazuje se, snažil jsem se nafouknout mým zvykem zobrazení pokaždé, když je řada byla právě zobrazenou. Jednoduše tím, že testování, zda řádek byl nafouknut I odstraněny tuto chybu, a já jsem s použitím stovek bitmapy. Jedná se vlastně o Spinner, ale základ adaptér pracuje všechny stejné pro ListView. Tato jednoduchá oprava také výrazně zlepšila výkonnost adaptéru.

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

    if(convertView == null){
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.spinner_row, null);
    }
...
Odpovězeno 24/02/2012 v 20:08
zdroj uživatelem

hlasů
12

Tento problém se stane pouze v Android emulátory. Také jsem čelí problému v emulátoru, ale když jsem zkontroloval v zařízení a pak to fungovalo v pohodě.

Proto zkontrolujte v zařízení. To může být spuštěn v přístroji.

Odpovězeno 13/08/2012 v 12:39
zdroj uživatelem

hlasů
12

Strávil jsem celý den testování těchto řešení a jediná věc, která pracovala pro mě je, že výše uvedené postupy pro získání obrazu a ručně volání GC, o němž vím, je neměl být nezbytné, ale je to jediná věc, která pracovala když jsem dal svou aplikaci při velkém zatížení testování přepínání mezi činnostmi. Moje aplikace je seznam miniatur v ListView v (řekněme, že aktivita a) a pokud kliknete na jeden z těch obrazů to se ti na jinou činnost (řekněme, že aktivita b), který ukazuje hlavní obraz pro danou položku. Když jsem se přepínat mezi těmito dvěma činnostmi, bych nakonec dostal chybu OOM a aplikace donutí zavřít.

Když bych se dostat na půl cesty dolů ListView by dojít k chybě.

Teď, když jsem se provést následující činnosti B, mohu projít celý ListView bez problému a jít dál a jít a jít ... a jeho dost rychle.

@Override
public void onDestroy()
{   
    Cleanup();
    super.onDestroy();
}

private void Cleanup()
{    
    bitmap.recycle();
    System.gc();
    Runtime.getRuntime().gc();  
}
Odpovězeno 27/03/2012 v 20:33
zdroj uživatelem

hlasů
11

Moje 2 centy: i vyřešit mé chyby OOM s bitmapami tím, že:

a) škálování moje obrázky koeficientem 2

b) za použití Picassovo knihovny v mé vlastní Adaptér pro ListView, s one-volání v getView takto:Picasso.with(context).load(R.id.myImage).into(R.id.myImageView);

Odpovězeno 14/07/2013 v 10:08
zdroj uživatelem

hlasů
10

používat tyto kód obrázkům v Vyberte si z sdcard nebo drewable převést bitmapový objekt.

Resources res = getResources();
WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = window.getDefaultDisplay();
@SuppressWarnings("deprecation")
int width = display.getWidth();
@SuppressWarnings("deprecation")
int height = display.getHeight();
try {
    if (bitmap != null) {
        bitmap.recycle();
        bitmap = null;
        System.gc();
    }
    bitmap = Bitmap.createScaledBitmap(BitmapFactory
        .decodeFile(ImageData_Path.get(img_pos).getPath()),
        width, height, true);
} catch (OutOfMemoryError e) {
    if (bitmap != null) {
        bitmap.recycle();
        bitmap = null;
        System.gc();
    }
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Config.RGB_565;
    options.inSampleSize = 1;
    options.inPurgeable = true;
    bitmapBitmap.createScaledBitmap(BitmapFactory.decodeFile(ImageData_Path.get(img_pos)
        .getPath().toString(), options), width, height,true);
}
return bitmap;

použijte disk cestu instend z ImageData_Path.get (img_pos) .getPath () .

Odpovězeno 24/01/2014 v 13:57
zdroj uživatelem

hlasů
10

Tento kód pomůže nahrát velké bitmapy z drawable

public class BitmapUtilsTask extends AsyncTask<Object, Void, Bitmap> {

Context context;

public BitmapUtilsTask(Context context) {
    this.context = context;
}

/**
 * Loads a bitmap from the specified url.
 * 
 * @param url The location of the bitmap asset
 * @return The bitmap, or null if it could not be loaded
 * @throws IOException
 * @throws MalformedURLException
 */
public Bitmap getBitmap() throws MalformedURLException, IOException {       

    // Get the source image's dimensions
    int desiredWidth = 1000;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;

    BitmapFactory.decodeResource(context.getResources(), R.drawable.green_background , options);

    int srcWidth = options.outWidth;
    int srcHeight = options.outHeight;

    // Only scale if the source is big enough. This code is just trying
    // to fit a image into a certain width.
    if (desiredWidth > srcWidth)
        desiredWidth = srcWidth;

    // Calculate the correct inSampleSize/scale value. This helps reduce
    // memory use. It should be a power of 2
    int inSampleSize = 1;
    while (srcWidth / 2 > desiredWidth) {
        srcWidth /= 2;
        srcHeight /= 2;
        inSampleSize *= 2;
    }
    // Decode with inSampleSize
    options.inJustDecodeBounds = false;
    options.inDither = false;
    options.inSampleSize = inSampleSize;
    options.inScaled = false;
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    options.inPurgeable = true;
    Bitmap sampledSrcBitmap;

    sampledSrcBitmap =  BitmapFactory.decodeResource(context.getResources(), R.drawable.green_background , options);

    return sampledSrcBitmap;
}

/**
 * The system calls this to perform work in a worker thread and delivers
 * it the parameters given to AsyncTask.execute()
 */
@Override
protected Bitmap doInBackground(Object... item) {

    try 
    { 
      return getBitmap();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
 }

}

Odpovězeno 31/10/2012 v 13:03
zdroj uživatelem

hlasů
9

Všechna řešení zde vyžadují stanovení IMAGE_MAX_SIZE. To omezuje zařízení s výkonnějším hardwarem a v případě, že velikost obrazu je příliš nízká, to vypadá ošklivě na obrazovce HD.

Přišel jsem s řešením, které pracuje se svým Samsung Galaxy S3 a dalšími zařízeními, včetně těch méně výkonných, lepší kvalitu obrazu, když se použije silnější zařízení.

Podstata toho je výpočet maximální velikost paměti přidělené pro aplikace na konkrétní zařízení a potom nastavte měřítko být co nejnižší, aniž by překročil tuto paměť. Zde je kód:

public static Bitmap decodeFile(File f)
{
    Bitmap b = null;
    try
    {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream(f);
        try
        {
            BitmapFactory.decodeStream(fis, null, o);
        }
        finally
        {
            fis.close();
        }

        // In Samsung Galaxy S3, typically max memory is 64mb
        // Camera max resolution is 3264 x 2448, times 4 to get Bitmap memory of 30.5mb for one bitmap
        // If we use scale of 2, resolution will be halved, 1632 x 1224 and x 4 to get Bitmap memory of 7.62mb
        // We try use 25% memory which equals to 16mb maximum for one bitmap
        long maxMemory = Runtime.getRuntime().maxMemory();
        int maxMemoryForImage = (int) (maxMemory / 100 * 25);

        // Refer to
        // http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
        // A full screen GridView filled with images on a device with
        // 800x480 resolution would use around 1.5MB (800*480*4 bytes)
        // When bitmap option's inSampleSize doubled, pixel height and
        // weight both reduce in half
        int scale = 1;
        while ((o.outWidth / scale) * (o.outHeight / scale) * 4 > maxMemoryForImage)
        scale *= 2;

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        fis = new FileInputStream(f);
        try
        {
            b = BitmapFactory.decodeStream(fis, null, o2);
        }
        finally
        {
            fis.close();
        }
    }
    catch (IOException e)
    {
    }
    return b;
}

I nastavit maximální velikost paměti používané tímto bitmapu, aby se 25% maximální přidělené paměti, může být nutné upravit tento vašim potřebám, a ujistěte se, že tato bitmapa vyčištěno a nezůstávají v paměti při dokončení jeho použití. Obvykle používám tento kód provést otočení obrazu (zdrojová a cílová bitmapu), takže moje app potřeba zavést 2 bitmapy v paměti ve stejnou dobu, a 25% mi dává dobrou vyrovnávací paměti, aniž by hrozilo z paměti při provádění otáčení obrazu.

Doufám, že to pomůže někdo tam venku ..

Odpovězeno 31/08/2013 v 04:04
zdroj uživatelem

hlasů
9

Takový OutofMemoryExceptionnemůže být zcela vyřešeny voláním System.gc()a tak dále.

S odkazem na cyklus aktivity Life

Aktivita státy jsou určeny OS sám s výhradou využití paměti pro každý proces a priority jednotlivých procesů.

Můžete zvážit velikost a rozlišení pro každý z bitmapových obrázků použitých. Doporučuji ke zmenšení velikosti, převzorkování na nižší rozlišení, se týkají návrhu galerií (jeden malý obrázek PNG a jednoho originálního).

Odpovězeno 08/08/2012 v 05:36
zdroj uživatelem

hlasů
8

Obecně android zařízení velikosti haldy je pouze 16MB (liší se od zařízení / OS viz rozmístit Heap Velikosti ), pokud načítání obrázků a překračuje velikost 16 MB, bude to vyhodit paměti výjimky, namísto použití Bitmap pro, nakládku obrázků z karty SD nebo z prostředků, nebo dokonce ze sítě se snaží pomocí getImageUri , nakládání bitmap vyžadují více paměti, nebo můžete nastavit bitmapu null, pokud svou práci s tímto bitmapu.

Odpovězeno 26/11/2012 v 06:48
zdroj uživatelem

hlasů
4

Zdá se, že obrazy, které jste používali, je velmi velký v size.so některých starších pády zařízení dochází v důsledku haldy paměti full.In starších zařízení (medu hřebenu nebo ICS nebo jakékoliv end modelů přístrojů nízkých), zkuste použít android:largeHeap="true"v souboru manifestu na základě žádosti značku nebo zmenšit velikost bitmapy pomocí níže kód.

Bitmap bMap;
BitmapFactory.Options options = new BitmapFactory.Options(); 
options.InSampleSize = 8;
bMap= BitmapFactory.DecodeFile(imgFile.AbsolutePath, options);

můžete také dát 4 nebo 12 nebo 16, aby se zmenšila velikost bitmapy

Odpovězeno 18/12/2014 v 09:40
zdroj uživatelem

hlasů
4
BitmapFactory.Options options = new Options();
options.inSampleSize = 32;
//img = BitmapFactory.decodeFile(imageids[position], options);

Bitmap theImage = BitmapFactory.decodeStream(imageStream,null, options);
Bitmap img=theImage.copy(Bitmap.Config.RGB_565,true);
theImage.recycle();
theImage = null;
System.gc();
//ivlogdp.setImageBitmap(img);
Runtime.getRuntime().gc();
Odpovězeno 24/07/2013 v 13:00
zdroj uživatelem

hlasů
4

Zkoušel jsem přístup Thomase Vervest, ale vrací ze stupnice od 1 do obrazového formátu 2592x1944 při IMAGE_MAX_SIZE 2048.

Tato verze pracoval pro mě na základě všech dalších připomínek poskytnutých jinými:

private Bitmap decodeFile (File f) {
    Bitmap b = null;
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options ();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream (f);
        try {
            BitmapFactory.decodeStream (fis, null, o);
        } finally {
            fis.close ();
        }

        int scale = 1;
        for (int size = Math.max (o.outHeight, o.outWidth); 
            (size>>(scale-1)) > IMAGE_MAX_SIZE; ++scale);

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options ();
        o2.inSampleSize = scale;
        fis = new FileInputStream (f);
        try {
            b = BitmapFactory.decodeStream (fis, null, o2);
        } finally {
            fis.close ();
        }
    } catch (IOException e) {
    }
    return b;
}
Odpovězeno 09/12/2012 v 22:45
zdroj uživatelem

hlasů
2

Chcete-li opravit OutOfMemory byste měli dělat něco takového zkuste tento kód

public Bitmap loadBitmap(String URL, BitmapFactory.Options options) {
                Bitmap bitmap = null;
                InputStream in = null;
                options.inSampleSize=4;
                try {
                    in = OpenHttpConnection(URL);
                    Log.e("In====>", in+"");
                    bitmap = BitmapFactory.decodeStream(in, null, options);
                    Log.e("URL====>", bitmap+"");

                    in.close();
                } catch (IOException e1) {
                }
                return bitmap;
            }

a

try {
                    BitmapFactory.Options bmOptions;
                    bmOptions = new BitmapFactory.Options();
                    bmOptions.inSampleSize = 1;
                    if(studentImage != null){
                        galleryThumbnail= loadBitmap(IMAGE_URL+studentImage, bmOptions);    
                    }

                    galleryThumbnail=getResizedBitmap(galleryThumbnail, imgEditStudentPhoto.getHeight(), imgEditStudentPhoto.getWidth());
                    Log.e("Image_Url==>",IMAGE_URL+studentImage+"");

                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
Odpovězeno 21/12/2013 v 12:10
zdroj uživatelem

hlasů
2

Hi Navštivte prosím na odkaz http://developer.android.com/training/displaying-bitmaps/index.html

nebo jen se snaží získat bitmapu s danou funkcí

private Bitmap decodeBitmapFile (File f) {
    Bitmap bitmap = null;
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options ();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream (f);
        try {
            BitmapFactory.decodeStream (fis, null, o);
        } finally {
            fis.close ();
        }

        int scale = 1;
        for (int size = Math.max (o.outHeight, o.outWidth); 
            (size>>(scale-1)) > IMAGE_MAX_SIZE; ++scale);

        // Decode with input-stram SampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options ();
        o2.inSampleSize = scale;
        fis = new FileInputStream (f);
        try {
            bitmap  = BitmapFactory.decodeStream (fis, null, o2);
        } finally {
            fis.close ();
        }
    } catch (IOException e) {
    }
    return bitmap ;
}
Odpovězeno 05/12/2013 v 11:22
zdroj uživatelem

hlasů
2

Použití tohoto pojmu To vám pomůže, po které nastavit imagebitmap na zobrazení obrázku

public static Bitmap convertBitmap(String path)   {

        Bitmap bitmap=null;
        BitmapFactory.Options bfOptions=new BitmapFactory.Options();
        bfOptions.inDither=false;                     //Disable Dithering mode
        bfOptions.inPurgeable=true;                   //Tell to gc that whether it needs free memory, the Bitmap can be cleared
        bfOptions.inInputShareable=true;              //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
        bfOptions.inTempStorage=new byte[32 * 1024]; 


        File file=new File(path);
        FileInputStream fs=null;
        try {
            fs = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        try {
            if(fs!=null)
            {
                bitmap=BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);
            }
            } catch (IOException e) {

            e.printStackTrace();
        } finally{ 
            if(fs!=null) {
                try {
                    fs.close();
                } catch (IOException e) {

                    e.printStackTrace();
                }
            }
        }

        return bitmap;
    }

Chcete-li vytvořit malý obrázek z velkého obrazu s výškou a šířkou, jako je 60 ° C a 60 ° C a přejděte na ListView rychle poté použijte tento koncept

public static Bitmap decodeSampledBitmapFromPath(String path, int reqWidth,
            int reqHeight) {

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

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

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

    public static int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {

        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            if (width > height) {
                inSampleSize = Math.round((float) height / (float) reqHeight);
            } else {
                inSampleSize = Math.round((float) width / (float) reqWidth);
             }
         }
         return inSampleSize;
        }

Doufám, že to pomůže hodně.

Můžete si vzít pomoc od vývojáře webu Zde

Odpovězeno 29/08/2013 v 07:34
zdroj uživatelem

hlasů
1

Přidejte následující řádky do vašeho Manifest.xml souboru:

<application

    android:hardwareAccelerated="false"
    android:largeHeap="true"

    <activity>
    </activity>

</application>
Odpovězeno 01/11/2018 v 06:02
zdroj uživatelem

hlasů
0

Osvědčené postupy, aby se zabránilo úniku paměti nebo OOM pro bitmapy

  1. Nevedou bitmapové odkazy na dlouho-žil do kontextové / aktivity.
  2. Pokud používáte velký rastrový obrázek jako pozadí nebo něco podobného ve své žádosti poté netahejte celého obrazu do hlavní paměti. Můžete použít insample velikosti majetku bitmapy, aby se velikost vašich potřeb obrazovky.
  3. Clean reference bitmap jakmile již nebudou používat.
Odpovězeno 25/06/2019 v 08:33
zdroj uživatelem

hlasů
0

To bude mít odpovídající bitmapu a snížit spotřebu paměti

JÁVA

Bitmap bm = null;

BitmapFactory.Options bmpOption = new BitmapFactory.Options();
bmpOption.inJustDecodeBounds = true;

FileInputStream fis = new FileInputStream(file);
BitmapFactory.decodeStream(fis, null, bmpOption);
fis.close();

int scale = 1;

if (bmpOption.outHeight > IMAGE_MAX_SIZE || bmpOption.outWidth > IMAGE_MAX_SIZE) {
    scale = (int)Math.pow(2, (int) Math.ceil(Math.log(IMAGE_MAX_SIZE / 
       (double) Math.max(bmpOption.outHeight, bmpOption.outWidth)) / Math.log(0.5)));
}

BitmapFactory.Options bmpOption2 = new BitmapFactory.Options();
bmpOption2.inSampleSize = scale;
fis = new FileInputStream(file);
bm = BitmapFactory.decodeStream(fis, null, bmpOption2);
fis.close();

Kotlin

val bm:Bitmap = null
val bmpOption = BitmapFactory.Options()
bmpOption.inJustDecodeBounds = true
val fis = FileInputStream(file)
BitmapFactory.decodeStream(fis, null, bmpOption)
fis.close()
val scale = 1
if (bmpOption.outHeight > IMAGE_MAX_SIZE || bmpOption.outWidth > IMAGE_MAX_SIZE)
{
  scale = Math.pow(2.0, Math.ceil((Math.log((IMAGE_MAX_SIZE / Math.max(bmpOption.outHeight, bmpOption.outWidth) as Double)) / Math.log(0.5))).toInt().toDouble()).toInt()
}
val bmpOption2 = BitmapFactory.Options()
bmpOption2.inSampleSize = scale
fis = FileInputStream(file)
bm = BitmapFactory.decodeStream(fis, null, bmpOption2)
fis.close()
Odpovězeno 08/03/2019 v 13:45
zdroj uživatelem

hlasů
0

Po pohledu přes všechny odpovědi, byl jsem překvapen, že nikdo nezmínil o Glide API pro manipulaci s obrázky. Great knihovna, a souhrny všechny složitosti řízení bitmapy. Můžete načíst a rychle měnit velikost snímků s touto knihovnou a jediný řádek kódu.

     Glide.with(this).load(yourImageResource).into(imageview);

Můžete získat úložiště zde: https://github.com/bumptech/glide

Odpovězeno 15/12/2017 v 18:38
zdroj uživatelem

hlasů
0

Použil jsem Descriptor File Decode který pracoval pro mě:

 FileInputStream  fileInputStream = null;
        try {
            fileInputStream  = new FileInputStream(file);
             FileDescriptor fd = fileInputStream.getFD();
            Bitmap imageBitmap = decodeSampledBitmapFromDescriptor(fd , 612,
                    816);
            imageView.setImageBitmap(imageBitmap);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(fileInputStream != null){
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

Kód pro dekódování článku Vzorek bitmapy z Descriptor File:

 /**
     * Decode and sample down a bitmap from a file input stream to the requested width and height.
     *
     * @param fileDescriptor The file descriptor to read from
     * @param reqWidth       The requested width of the resulting bitmap
     * @param reqHeight      The requested height of the resulting bitmap
     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
     * that are equal to or greater than the requested width and height
     */
    public static Bitmap decodeSampledBitmapFromDescriptor(
            FileDescriptor fileDescriptor, int reqWidth, int reqHeight) {

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

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

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
    }

    /**
     * Calculate an inSampleSize for use in a {@link android.graphics.BitmapFactory.Options} object when decoding
     * bitmaps using the decode* methods from {@link android.graphics.BitmapFactory}. This implementation calculates
     * the closest inSampleSize that will result in the final decoded bitmap having a width and
     * height equal to or larger than the requested width and height. This implementation does not
     * ensure a power of 2 is returned for inSampleSize which can be faster when decoding but
     * results in a larger bitmap which isn't as useful for caching purposes.
     *
     * @param options   An options object with out* params already populated (run through a decode*
     *                  method with inJustDecodeBounds==true
     * @param reqWidth  The requested width of the resulting bitmap
     * @param reqHeight The requested height of the resulting bitmap
     * @return The value to be used for inSampleSize
     */
    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) {

            // Calculate ratios of height and width to requested height and width
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);

            // Choose the smallest ratio as inSampleSize value, this will guarantee a final image
            // with both dimensions larger than or equal to the requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;

            // This offers some additional logic in case the image has a strange
            // aspect ratio. For example, a panorama may have a much larger
            // width than height. In these cases the total pixels might still
            // end up being too large to fit comfortably in memory, so we should
            // be more aggressive with sample down the image (=larger inSampleSize).

            final float totalPixels = width * height;

            // Anything more than 2x the requested pixels we'll sample down further
            final float totalReqPixelsCap = reqWidth * reqHeight * 2;

            while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
                inSampleSize++;
            }
        }
        return inSampleSize;
    }
Odpovězeno 20/07/2017 v 15:46
zdroj uživatelem

hlasů
0

Pokud jste líní jako já. můžete začít používat Picassovo knihovnu načíst obrázky. http://square.github.io/picasso/

Picasso.with(context).load(R.drawable.landing_screen).into(imageView1); Picasso.with(context).load("file:///android_asset/DvpvklR.png").into(imageView2); Picasso.with(context).load(new File(...)).into(imageView3);

Odpovězeno 12/07/2017 v 14:38
zdroj uživatelem

hlasů
-8

Po nastavení je bitmapu imageview, recyklovat to takhle:

bitmap.recycle();
bitmap=null;
Odpovězeno 29/03/2013 v 07:56
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more