i have a HashMap like this
HashMap<String, BitmapDrawable> bitmapDrawables = new HashMap<String, BitmapDrawable>();
Now i have a method which will return the drawable:
public static BitmapDrawable getDrawable(String fileName, Context context,Bitmap bitmap) {
BitmapDrawable drawable = bitmapDrawables.get(fileName);
if (drawable == null) {
drawable = convertBitmapToDrawable(bitmap, context);// will convert the bitmap to drawable
bitmapDrawables.put(fileName, drawable);
}
return drawable;
}
It works fine but some times it will not return the proper drawable, like i have 2 Activities A and B,in Activity A i have a button with drawable set, now i move from A -> B and then come back to A at that time the drawable is not loading, but when i touch that button the drawable is visible.
Why this is happening?, i have removed the haspMap and checked it its loads properly and when i move from A->B and come back to A,but if i dont use the Hashmap there is lag in the screens.
i am using the getDrawable() in this fashion:
button.setBackgroundDrawable(getDrawable(name,context,bitmap);
You can use
button.setBackgroundDrawable(getDrawable(name,context,bitmap)
in method onResume(). By the way, your implementation is not recommended, will cause memory leak easily. See this for more detail
Related
I have a variable Bitmap image. I have imageButton in my fragment. I can change image of imageButton with Glide.with().load().into(). But I want not to just change image but to save it into Bitmap variable so I can use it for some other task. I tried this
Bitmap image = Glide.with(getContext()).asBitmap().load(imagePath).submit().get();
imageButton.setImageBitmap(image);
But image of imageButton does not change. What's wrong with first line then? Because I am pretty sure that problem is there but don't understand yet what is exactly wrong.
A solution is to do
Bitmap image = BitmapFactory.
decodeStream(getContext().
getContentResolver().
openInputStream(selectedImage));
imageButton.setImageBitmap(image);
Where selectedImage is Uri selectedImage = data.getData() of onActivityResult method, but it will be total mess because of size of bitmap, so we have to use createScaledBitmap, I don't like it. For some reason Bitmap image = BitmapFactory.decodeFile(imagePath) doesn't work, imageButton just becomes tiny grey square, and I didn't find a solution for this.
first of all why are using the imageButton..use imageView it will good than
imagebutton and it will work
I don't know if you should even think about doing this in some serious project but for now it did what needs to be done for me. Earlier I declared private Bitmap jopa.
Glide.with(getContext()).asBitmap().
load(selectedImage).override(500,500).
into(new CustomTarget<Bitmap>()
{
#Override
public void onResourceReady(#NonNull Bitmap resource, #Nullable Transition<? super Bitmap> transition) {
imgShare.setImageBitmap(resource);
jopa = ((BitmapDrawable)imgShare.getDrawable()).getBitmap();
}
#Override
public void onLoadCleared(#Nullable Drawable placeholder) {
}
});
Now Bitmap jopa can be used for other tasks. I hope. Tested it to change picture of another imageview, it worked, so I'll pray it will work further. Full onActivityResult code here. Don't want question to get too messy
I have a AnimationDrawable that i initialise before starting the animation and recycle it right as it finishes.. the problem is that when i want to start the animation again, i reinitialise everything but still gives an exception
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap#2bbad018
here's my code
public ImageView radarImageView;
public AnimationDrawable animationDrawable;
public void animationStart() {
// animationStop();
radarImageView = (ImageView) findViewById(R.id.radarIV);
radarImageView.setBackgroundResource(R.drawable.sensor_animation);
animationDrawable = (AnimationDrawable) radarImageView.getBackground();
animationDrawable.start();
}
public void animationStop() {
animationDrawable.stop();
for (int i = 0; i < animationDrawable.getNumberOfFrames(); ++i){
Drawable frame = animationDrawable.getFrame(i);
if (frame instanceof BitmapDrawable) {
((BitmapDrawable)frame).getBitmap().recycle();
}
frame.setCallback(null);
}
animationDrawable.setCallback(null);
// animationDrawable = null;
// radarImageView.setBackgroundResource(0);
}
Why does it not reinitialise the whole thing again?
The problem is because when you Bitmap.recycle() is called on the bitmap you cannot reuse it.
Also as you are calling setBackgroundResources(R.drawable.sensor_animation) you are referring to the same object which its bitmaps were recycled previously.
As a solution, you either have to create a new drawable every time or do not recycle that instance.
If you are worries about the memory usage try to use smaller bitmaps. Also using the correct sizes for different screen densities would help.
It appears that, when I call setImageDrawable(null) for an ImageView, the bitmap is not being released. What can I do to force it to free the bitmap memory?
I have an activity that needs to display a large number of drawables, but not at the same time. I have extended ImageView as shown here. The XML layout file declares instances of this, with the "src" attribute set to "#null". In replacement, I have a custom attribute to hold the drawable resource id.
public class ImageViewHolder extends ImageView
{
int srcId = 0;
//-----------------------------------------------------------------------------
public ImageViewHolder (Context context, AttributeSet attrs)
{
super (context, attrs);
TypedArray a = context.obtainStyledAttributes (attrs, R.styleable.ImageViewHolder, 0, 0);
srcId = a.getResourceId (R.styleable.ImageViewHolder_src, 0);
a.recycle();
}
//-----------------------------------------------------------------------------
public void showDrawable (boolean makeVisible)
{
if (makeVisible)
{
// Drawable d = getResources().getDrawable (srcId);
// setImageDrawable (d);
setImageResource (srcId);
}
else // hide & free memory
{
Bitmap bitmap = ((BitmapDrawable)getDrawable()).getBitmap();
setImageResource(0);
bitmap.recycle();
// setImageDrawable (null);
}
}
}
I've tried using SetImagerResource() instead but get the same results. I also tried calling System.gc() after clearing the drawable and that only deferred the point where my device ran out of memory.
Any ideas?
Instead of using
setImageResource (srcId);
use
Resources r = getResources();
Bitmap b = BitmapFactory.decodeResource (r, srcId);
setImageBitmap (b);
This bypasses the Resources() caching and just recreates the bitmap each time you need it. After testing this code, I'm still eventually getting an out-of-memory error but it's taking much longer to get there. I'm going to assume it's being caused by something else. For now, that's enough time spent on this problem :)
I'm using the loadermanager for my app. On Orientation change my app can reload the TextView, but the imagestream for my drawable is not loaded the second time. On the first load the picture shows ,but after an orientation change it stays in its unchanged state. (in my case , a white square)
#Override
public void onLoadFinished(Loader<Person> loader, Person p) {
tvProfileName.setText(p.getName());
Log.i("img stream", ""+p.getImageStream());
Bitmap b = BitmapFactory.decodeStream(p.getImageStream());
Drawable d = new BitmapDrawable(getResources(), b);
ivMenuPhoto.setImageDrawable(d);
}
The setText is working and my name is loaded, even after the orientation change. But the setimagedrawable is not working. The p.getImageStream is not null...
Is my drawable maybe set before the layout is finished changing? I'm just very confused, because my TextView is working.
edited for my solution:
I added a Drawable attribute in the Person Object. So the loader can also hold that part. Then I created the getters and setters. And then I added the onResume to also set my drawable after the orientation change
#Override
public void onLoadFinished(Loader<Person> loader, Person p) {
tvProfileName.setText(p.getName());
Drawable d = new BitmapDrawable(getResources(), p.getPersonphoto());
this.personPhoto = d;
ivMenuPhoto.setImageDrawable(d);
}
#Override
protected void onResume() {
super.onResume();
ivMenuPhoto.setImageDrawable(this.personPhoto);
}
I have some CustomButton, and at some point, a background is drawn from a base64String into a BitmapDrawable, which is applied to the CustomButton. Within the total lifespan of the application, this can happen multiple times. This caused a OutOfMemoryError: bitmap size exceeds VM budget, and after some digging on StackOverflow, this happened because the Bitmaps were not recycled. So I tried to handle this with some code that is executed each time another background was applied (this code comes from the CustomButton class):
public void recycleBackground() {
BitmapDrawable bd = null;
Drawable bg = getBackground();
if (bg != null) {
bg.setCallback(null);
if (bg instanceof BitmapDrawable) {
bd = (BitmapDrawable) bg;
if (!bd.getBitmap().isRecycled()) bd.getBitmap().recycle();
}
bd = null; //just precautionous
bg = null; //also just a precaution
}
Yet, the memory is slowly (because background images are not all that large) but surely flooded. What am I missing or doing wrong? I combined the above code from some different questions/answers from SO. I can find a lot on recycling Bitmaps, not so much on the recycling of Drawables. Maybe that's what I'm doing wrong?