How can I get the bitmap from a recyclerview?
recyclerview.setDrawingCacheEnabled(true);
Bitmap bitmap = recyclerview.getDrawingCache();
recyclerview.setDrawingCacheEnabled(false);
Bitmap newBmp = bitmap.copy(bitmap.getConfig(),true);
And I'm getting an exception
java.lang.IllegalStateException: Can't copy a recycled bitmap
Change your code like this:
recyclerview.setDrawingCacheEnabled(true);
Bitmap bitmap = recyclerview.getDrawingCache();
Bitmap newBmp = bitmap.copy(bitmap.getConfig(),true);
recyclerview.setDrawingCacheEnabled(false);
Basically what's happening here is that when you call setDrawingCacheEnabled(false), the underlying Bitmap object that has been created is recycled. If you copy the bitmap before you recycle it, it should work as expected.
Related
I Have a recycler view that shows multi bitmap from the SQLite database. When the number of bitmaps increases, recycler view scrolled with lag, In addition, The whole program slows down.
I save bitmap from a view to a database like this (convert bitmap to byte):
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getWidth(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, stream);
DatabaseHelper.updateData(id, stream.toByteArray());
And convert the byte to a bitmap in onBindViewHolder adapter like this:
byte[] byte = items.get(position).getImageByte();
Bitmap bitmap = BitmapFactory.decodeByteArray(byte, 0, byte.length);
holder.ivShot.setImageBitmap(bitmap);
And this is my fragment that initializing recycler view:
ModelArrayList = DatabaseHelper.getData();
Adapter = new Adapter(ModelArrayList, DatabaseHelper);
recycler.setHasFixedSize(true);
recycler.setLayoutManager(new GridLayoutManager(context, 2));
recycler.setAdapter(Adapter);
How I can fix this error?
I don't know how you can reduce the size of the bitmap for better performance, But I tested it with the Glide library and the lag issue was solved.
Glide.with(context).load("your byte")
.placeholder("default image")
.into(viewHolder.imageView);
Bitmap loading is a very sensitive and complicated topic, as bitmap size gets larger you will face more memory issues, and hence the lag.
Your best way to load bitmaps in recyclerview is to keep your bitmaps in Files and load them using some well known efficient libraries like Glide.
You can create a less memory-hungry version of the image called thumbnail.
Then pass the thumbnail to the Recycler-View. Android has an API for this
import android.media.ThumbnailUtils
Bitmap thumbnailBitmap = ThumbnailUtils.extractThumbnail(originalBitmap, width, height);
Make sure to get rid of the original Bitmap afterwards.
originalBitmap.recycle();
I have a NetworkImageView where I download images from a server. However, the requirement is to have the ability to rotate the image after downloading the image. I have a rotate image function but I need to get the Bitmap associated to the NetworkImageView in order for me to rotate the bitmap. How can I access the BitMap from a NetworkImageView?
You can use below method to get bitmap of any view.
Bitmap bitmap = viewToBitmap(mImageView);
Bitmap bitmap = viewToBitmap(mLinearlayout);
Bitmap bitmap = viewToBitmap(mRelativelayout);
public Bitmap viewToBitmap(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
Hope this helps
UPDATE
Create a volley image request.
After the image has been loaded and set inside the NetworkImageView this code will work. Else it will return a Null pointer since there is no view/image inside the NetworkImageView
mNetworkImageView = (NetworkImageView) view.findViewById(R.id.networkImage);
Bitmap bitmap = ((BitmapDrawable) mNetworkImageView.getDrawable()).getBitmap();
There is another way to use Volley and obtain the Bitmap.
Create an ImageRequest
inside the onResponse(), obtain the Bitmap and set it to your ImageView (Not NetworkImageView). I had mentioned this method in the comments above.
If I create an object and assign it to a variable:
Obj obj1 = null;
obj1 = myFunction(params);
(here myFunction creates a complex object)
And later I reassign the variable:
obj1 = myFunction(otherparams);
Does in that moment a memory leak occur, because I did not destroy the previous object?
Here is the real situation:
Bitmap bmp;
bmp = drawMyBitmap(3);
//... some code
bmp = drawMyBitmap(4);
Will a memory leak happen here?
Of cource, I know that I must call bmp.recycle, but I can't do it, because the real code is the following:
Bitmap bmp;
bmp = drawMyBitmap(3);
imageView.setImageBitmap(bmp);
//... some code
// if I try to do recycle here - I receive java.lang.IllegalArgumentException: Cannot draw recycled bitmaps
// But I need to recreate bitmap every some minutes
bmp = drawMyBitmap(4);
imageView.setImageBitmap(bmp);
So, how can I recycle the bitmap and avoid memory leaks?
As I understand, your problem is just you can't recycle your Bitmap cause it's used.
It's pretty naive, so maybe it's wrong, but do this:
imageView.setImageBitmap(bmp);
//... some code
Bitmap tmp = bmp;
bmp = drawMyBitmap(4);
imageView.setImageBitmap(bmp);
tmp.recycle(); // As it's not anymore referenced by the ImageView, you can recycle the Bitmap safely
I didn't test it. Give feedback.
In the first case, you will release the first object's reference so the garbage collector will destroy it, leaving the second one live on memory because of new reference.
In the second case, if you are setting bitmaps to ImageViews, you can not recycle them because the view will not have the bitmap to draw the image and it will throw to you a bitmap recycled exception, so you are not "leaking" to much memory keeping 2 bitmaps on memory.
Try to use bitmap options to create them to optimise your memory comsuption if you want.
Bitmap bmp;
bmp = drawMyBitmap(3);
imageView.setImageBitmap(bmp);
//... some code
// if I try to do recycle here - I receive java.lang.IllegalArgumentException: Cannot draw recycled bitmaps
// But I need to recreate bitmap every some minutes
Bitmap temp = bmp; //try this
bmp = drawMyBitmap(4);
imageView.setImageBitmap(bmp);
temp.recycle();
I want to add some text on top of an image.
I read the image from the sd card and set it to a Bitmap variable.
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
Then I added it to a canvas. The code I used is given below,
Canvas c = new Canvas(myBitmap);
But when I added this line, the app crashed at that point. Why is it and how can i solve this ??
Note : Above mention code lines are inside onActivityResult method.
You app crash because your
BitmapFactory.decodeFile
return a immutable bitmap and public Canvas (Bitmap bitmap) only accept a mutable bitmap.
To solve your problem you must convert your immutable Bitmap into mutable see here the method
If you target only >= API 11 , you can use
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), options);
I am loading a bitmap from a resource like so:
Bitmap mBackground = BitmapFactory.decodeResource(res,R.drawable.image);
What I want to do is make some changes to the bitmap before It gets drawn to the main canvas in my draw method (As it would seem wasteful to repeat lots of drawing in my main loop when it isn't going to change). I am making the changes to the bitmap with the following:
Canvas c = new Canvas(mBackground);
c.drawARGB(...); // etc
So naturally I get an exception
java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor
So to avoid that I made a copy of the bitmap so that it is mutable
Bitmap mBackground = BitmapFactory.decodeResource(res,R.drawable.image).copy(Bitmap.Config.ARGB_8888, true);
Which avoid the problem however it sometimes causes OutOfMemoryExceptions, do know any better ways of achieving what I want?
Use decodeResource(Resources res, int id, BitmapFactory.Options opts) and specify inMutable in the options.
http://developer.android.com/reference/android/graphics/BitmapFactory.html
You'd better use RapidDecoder.
import rapid.decoder.BitmapDecoder;
Bitmap mBackground = BitmapDecoder.from(res, R.drawable.image)
.mutable().decode();
Works for API level 8.
Instad of yours:
Bitmap mBackground = BitmapFactory.decodeResource(res,R.drawable.image);
Use:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
Bitmap mBackground = BitmapFactory.decodeResource(res,R.drawable.image, options);