2

I'm loading a bitmap to use as a texture in my OpenGLES 2.0 app

If I load and use the bitmap via Bitmapfactory then all is OK. Like so:

Load

 public void loadBitmaps{

    backgrounds= BitmapFactory.decodeResource(view.getResources(), R.drawable.backgrounds, BMFOptions);
    ...

Use

//Apply as texture to OpenGL Quad

Recycle

backgrounds.recycle();

.

Now, the problem...........

.

When I load the bitmap as a bitmapDrawable, I get problems (explained below code). Like so:

.

Declare BitmapDrawable at class level

public class Res{

    BitmapDrawable bd;
    ...

Load

public void loadBitmaps(){

    bd = (BitmapDrawable) view.getResources().getDrawable(R.drawable.backgrounds);
    backgrounds = bd.getBitmap();
    ...

Use

//Apply as texture to OpenGL Quad

Recycle

backgrounds.recycle();

When doing this, it works the first time, but if I then press back to exit, and relaunch the app, the textures don't show and all I get are black quads.

If I do any of the following it solves the problem and I would like to know why......

  • Either move the declaration of bd from a class variable so I'm using:

BitmapDrawable bd = (BitmapDrawable) view.getResources().getDrawable(R.drawable.backgrounds);

  • Or simply do this after creating the bitmap:

bd = null;

  • finally, I can also, just not recycle the bitmap, but this isn't an option

Note I need to access the bitmap in this way rather than using BitmapFactory as I'm accessing it via an XML Alias.

Zippy
  • 3,826
  • 5
  • 43
  • 96

1 Answers1

3

Drawable instances are cached and shared, so when you do a call to getDrawable() it will load the one it currently has cached rather than creating a new bitmap. If you recycle the underlying bitmap, that's going to cause problems with future uses. What you likely want to do is make a copy of the drawable before modifying it:

BitmapDrawable bmpDrawable = (BitmapDrawable) view.getResources()
        .getDrawable(R.drawable.backgrounds);
Bitmap original = bmpDrawable.getBitmap();
Bitmap copy = original.copy(original.getConfig(), true);

See this blog post for more info on drawable mutations.

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • Thanks @kcoppock for this information, I will read the blog for sure, but can you tell me, is holding a copy, bad (memory-wise), and (again memory wise), is there anything wrong with the method's I've found, for example just nulling bd in my example above? My bitmaps are quite large and as I'm applying them as textures, (they are texture atlases), So I want to get rid of the underlying bitmap once that's been done. Therefore, I don't want to hold them anywhere else. I'm just trying to be as memory concious as I can - thanks – Zippy Sep 15 '14 at 23:33
  • Also what I don't get is that I'm actually exiting my app and re-launching it, so should everything not be as it was when the app was first launched? – Zippy Sep 15 '14 at 23:42
  • Just closing your app doesn't clear the process from memory, so it's not guaranteed that they'd be re-loaded. Is there any way you could avoid using XML aliases for these and just load the bitmaps directly? I'm fairly certain there's no way to retrieve those without going through Drawables, in which case you have no control over when the resources are recycled. – Kevin Coppock Sep 15 '14 at 23:44
  • Also, I updated my answer since I realized `mutate()` doesn't actually change the underlying bitmap -- just the state of the drawable. – Kevin Coppock Sep 15 '14 at 23:47
  • I looked for a long time for ways to get to the Aliases, but unfortunately, it seems using drawables is my only option. Would nulling the object and recycling the bitmap as I'm currently doing, be an effective workaround (to force it to create a new one each time) - I'm thinking that would be the best for freeing up memory - would you agree? I don't really want instances of this large bitmap sitting around once it's been applied to my OpenGL Objects or the app exited. I have many other bitmaps that I load with Bitmapfactory and I recycle them all. Thanks for your help. – Zippy Sep 15 '14 at 23:49
  • If you load with resources, you cannot recycle the underlying bitmap or you're going to cause all sorts of crazy to happen. Nulling the object won't cause Android to release the cache (it should handle that automatically when more memory is needed). – Kevin Coppock Sep 15 '14 at 23:52
  • Thanks @Kcoppock, I really want to understand something. If I load the bitmap as a drawable, bind it as a GL texture, then recycle the bitmap (as it shouldn't be required anymore, in my understanding, the GL texture is basically a copy of the bitmap) - why would the recycling cause problems as it would not be needed anymore during that session ie, until the app is exited and re-launched. I'm just asking as I'm a bit confused about that part!!!! Otherwise, your method seems reasonable. – Zippy Sep 16 '14 at 00:00
  • Your application process can stay in memory longer (sometimes much longer) than your activities. Even after all of your activities are finished, your application can stay in memory and hold onto cached resources and may be kept alive for a while for faster launching, or running a service, or receiving broadcasts, etc.). Basically, you're recycling something that Android is still using (even though you aren't). – Kevin Coppock Sep 16 '14 at 00:05
  • Ah, I see. That makes sense. So basically, I can do the recycle, but it would mean that I'm forcing my resoures to be re-loaded, whereas if I didn't recycle them they *could* still be available after the user exited the app if they decided to re-launch. I never really thought of it that way, although I still don't get why it would cause problems for me to recycle and re-load each time, but thanks I understand your thinking with regards to your answer. Answer accepted. – Zippy Sep 16 '14 at 00:09
  • By the way @Kcoppock, your original answer (use .mutate()) actually works too! – Zippy Sep 16 '14 at 00:26
  • 1
    Weird. It *shouldn't*, haha. I wouldn't necessarily rely on that to work; they may have changed how that works internally since that blog post went up. Interesting to know though! – Kevin Coppock Sep 16 '14 at 00:27