RecycleView List with no fixed child height - android

I'm dealing with a problem with the RecycleView while I'm scrolling and loading images from the web. The size of the image PLUS the behaviour of the ImageView component (width = match pratent, height = wrap content) determines the height of the child. I thought that a good workaround for it was to ask the image height and width from the server. That way I would be able to resize the child at the very moment that it is created, avoiding the odd behaviour of resizing after the image is loaded. In order to do that, I started creating Bmp drawables with the correct size of the image that would be loaded and putting it as placeholder using the picasso (placehold(Drawable)).
With that, I've fixed the resize problem, but then I started to get OutOfmemory because of the creation of the BMP. is there a better approach to if it?

Have you ever try BitmapFactory.Options?
There is a way to fetch the image attributes before loading entire bitmap data as :
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;
ref https://developer.android.com/topic/performance/graphics/load-bitmap.html

Related

Glide loads wrong image size

I use simple:
Glide.with(this).load(logoPath).apply(RequestOptions.circleCropTransform()).into(businessIcon)
Size of logoPath on server is 48*48, when I put wrap_content attribute on ImageView dimensions, final image is 1280*1280.
What am I doing wrong?
There seems to be some misunderstanding in what Glide gets from the server.
It is just regular file, and it will be fetched as-is, it is extremely unlikely somebody could get higher resolution image by downloading.
(If you really can, you could make a lot of money )
So the actual problem is how this image file is displayed.
You could use ImageView attribute android:scaleType="center" to force no scaling to be performed.
You could also download the Image, convert it to Bitmap and get its attributes. Something simmilar to this.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(logoPath, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
And then use these values for fixed dimensions in Glides method .override()

Images scales defferently in setImageDrawable() and setImageBitmap()?

I am new in android development. I have an issue regarding the image scaling in my app. When i set images using setImageDrawable() images look proper like in screenshot:
But if i set image using setImageBitmap() method it does not look proper. Some black color occurs around it like in screenshot bellow:
I have tried it in multiple applications and i observed that in some applications the image size is becoming smaller than the size ofter setting image through setImageDrawable() or setImageResource().
the reason for setting images through setImageBitmap() is that i want to set images to the imageviews which are kept in assets folder and not in drawable.
Following is the code i used to create a bitmap and set it to imageview:
BitmapFactory.Options opts = new Options();
opts.inPurgeable = true;
try
{
Bitmap preview_bitmap = BitmapFactory.decodeStream(assetManager.open(drawableFolder+"/"+tmpArr[0]),null,opts);
view.setImageBitmap(preview_bitmap);
}
catch (Exception e)
{
LNLog.writeTOErrorToLog(e.getMessage());
}
So, please can anyone tell me where i'm i going wrong or missing something to set.
I tried to set Options but did not worked. I want to set images as in first screenshot that is how they looks by using setImageDrawable().
Thanx in advance.
Note: in screenshots images are referent in text on it only.IF i set hindi images i.e. the images on which text is in hindi language using setImageDrawable() then they looks proper as in like in screen shot one.So , no issue of image files.
You can get rid of the black borders by using
android:adjustViewBounds="true" in xml
or
imageView.setAdjustViewBounds(true) in Java.
EDIT:
Then try using drawable only
Drawable d = Drawable.createFromStream(assetManager.open(filePath), null);
view.setImageDrawable(d)
This worked for me :
try
{
view.setAdjustViewBounds(true);
int height = view.getDrawable().getIntrinsicHeight();
int width = view.getDrawable().getIntrinsicWidth();
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPurgeable = true;
opts.inScaled = true;
Bitmap preview_bitmap = BitmapFactory.decodeStream(assetManager.open("drawable-mdpi/FAQ_hi_in.png",null,opts);
Bitmap bmp = Bitmap.createScaledBitmap(preview_bitmap, width, height, true);
view.setImageBitmap(bmp);
}
In this code I have taken the height and width of actual image and then scaled my bitmap to that height and width. Then I converted this scaled bitmap to drawable and set it into my ImageView, thats it. It resolved my problem of black border around image.

OutOfMemory when loading large Background Image

I am using android:background to give a background image to android layout.
After putting some images I get this exception :
08-24 00:40:19.237: E/dalvikvm-heap(8533): Out of memory on a 36000016-byte allocation.
how can I use large images as backgrounds on android?
can I expand the application heap memory? or is it something not good to do ?
Please have a look at my related question:
High resolution Image - OutOfMemoryError
Try to minimize the memory usage of your application by keeping the background image as small as possible.
This can be done via:
cropping the image so that it fits the screen
compress the image further (use e.g. photoshop) before even using it in the app
use the below method to load your bitmap
recycle the bitmap as soon as you no loger need it
make sure you do not keep multiple instances of it in memory
set the reference to null after using the bitmap
Make sure the images you set as a background are loaded properly (e.g. cropped in size, for example fit the screen size) and released from the memory as soon as they are no longer needed.
Make sure you have only one instance of your Bitmap in memory. After displaying it, call recycle() and set your reference to null.
This is how you could load your images:
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);
}
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;
}
return inSampleSize;
}
Thanks to Adam Stelmaszczyk for this beautiful piece of code.
I have experienced a similar issue due to background images in layouts. The normal size of a memory allocation of an image should be height*width*4 bytes (in mode ARGB_8888, the default mode).
If you see and allocation of 30MB when showing an activity there must be some problem. Check if you are placing your background images in the drawable folder. In that case, the system must scale that image to the specific density of the screen, causing a big memory overhead.
Solutions:
Place a specific version of the background image in each drawable folder (mdpi, hdpi, xhdpi...).
Place the background image in a special resource folder called "drawable-nodpi". The system won't try to scale images placed in this directory so only an streching process is carried out and the memory allocated will be the expected.
More information in this answer
Hope this helps.
I had the same problem and fixed it by the following:
Create a drawable-nodpi folder and put your background images in there.
Use Picasso to display the images http://square.github.io/picasso/
Display them with .fit() and .centerCrop() and Picasso scales the image if it needs to
ImageView ivLogo = (ImageView) findViewById(R.id.ivLogo);
Picasso.with(getApplicationContext())
.load(R.drawable.logo)
.fit()
.centerCrop()
.into(ivLogo);
If you do run out of memory somehow, Picasso will simply not display the image, instead of giving you an OOM error. I Hope this helps!
can I expand the application heap memory?
Yes, you can. Just set android:largeHeap:="true"in your Manifest.xml.
<application
android:name="com.pepperonas.libredrive.App"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:largeHeap="true"
android:label="#string/app_name"
android:launchMode="standard">
Use Glide which will help you cache images and load the from memory
Glide
.with(/*context*/)
.load(/*urlToImage*/)
.thumbnail(0.5f/*scale*/) //you can even downscale the image
.into(imageView);
Secondly with Glide you can pause and resume request by observing scrolling behaviour by using the OnScrollChangedListener
if(scrollState == SCROLL_STATE_IDLE){
Glide.with(this /*context*/).resumeRequests();
} else if(scrollState == SCROLL_STATE_TOUCH_SCROLL ||
scrollState == SCROLL_STATE_FLING){
Glide.with(this).pauseRequests();
}
For bitmap Glide is best .
Glide.with(getContext()).load(img_url_1).apply(new RequestOptions().override(Target.SIZE_ORIGINAL)).into(imageView1);

Getting View size inside a BaseAdapter.getView()

I have an activity wich contains a ListView, the list is a thumbnail on the left and some text on the right, pretty much like a contact list. The thing is, the thumbnail is loading from an absolute path from the sdcard, and each image size is about 5mb. For avoiding running out of memory I created the classes in this tutorial which loads only a scaled version of the images and doesn't take a lot of memory.
Well, what's the problem? Since, I have to pass the width and the height (in px) that I want the image to be resized, but for differente devices I would have a problem setting absolute values. So, I just tried passing the view through args, and just manipulate it in my class to get the width and height, nice eh? Ok, but it didn't work, since the thumbnail hasn't been draw yeat (i guesss), I can't take his size values.
How can I get the size inside the method getView() from my lisview adapter?
/** short passage of getView() method */
ImageView image = (ImageView) view.findViewById(R.id.image_thumb);
Bitmap bMap = BitmapAdjusted.decodeSampleBitmap("/sdcardpath/",
image); // "image" is the view passed by args
image.setImageBitmap(bMap);
Here's the problem:
public static decodeSimpleBitmap(String path, View view){
/** unworth previous code */
int width = view.getWidth(); // always give zero, getMeasuredWidth() too
int height = view.getHeight(); // always give zero
// options is BitmapFactory.Options class, declared before that do the magic
options.inSampleSize = calculateInSampleSize(options, width, height);
}
Thanks!

android - query CAMERA folder images with width and height

is it possible to query for images from CAMERA folder with height and width?
I am querying it with only URL right now. I want to avoid loading image into Bitmap and I need to have width and height of it beforehand so I can figure out proper scaling. Right now some of the photos I load can be really large size and some can be tiny. If I set same scaling on them they don't look right. Small images get resized for no reason. Knowing width and height would solve this. Also I cannot sample load a bitmap because that causes memory issue when images are really large, like those taken with 3 megapixel camera.
Here is how I load them:
https://stackoverflow.com/questions/5710036/android-camera-folder-images-not-all-show-up
Thank you.
You should do decoding for the image without getting its whole data.
the reason it doesn't exist on the DB is that the user can always modify the images to have different dimensions than the original one.
in order to get just the minimal information of the bitmap, use something like:
public static BitmapFactory.Options getBitmapOptions(final String filePath) {
final BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, bitmapOptions);
return bitmapOptions;
}

Categories

Resources