I have 3 or 4 image paths that I use to load an image so I set it to an imageview. Why does it take long? Or better asking is there a way to make it faster? At the end of the day I am loading to fit an imageview of less than 60 dp hight and width
Uri mainImgeUri = Uri.parse(imagePath);
InputStream imageStream;
try {
imageStream = mActiviy.getContentResolver().openInputStream(mainImgeUri);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream, null, options);
mainImageIV.setImageBitmap(yourSelectedImage);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
USE CASE:
What happens is that a user will add 5 images (and he get to choose them from Gallery which is mostly taken by phone camera). He hit save and my app stores the path to them in an sqlite database. Then when the user opens the app again to see them, my app query the db to get the paths to all the images and executes the code above x number of times so all the image views are loaded with the intended images
Take a look at http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
It explains how to calculate the correct inSampleSize based on the required dimensions of the output image. It also explains how to reference large bitmaps without having to load all their pixel data into memory.
The idea is that you resample bigger images and only load the smaller ones into memory making the whole process much more efficient. The example code is accessing a bitmap from resources, but this can easily be modified for your needs.
The important things to look out for in the example are inJustDecodeBounds and calculateInSampleSize.
Related
I'm running into issues with the images in my gallery being much much larger than I need them to be.
I've looked for ways to reduce their size before I actually pull them in, but I'm just not quite putting it together as most of what I'm finding deals with BitMap resources and not a BitMap that already exists in the gallery.
So, basically, I am getting the image like so,
imageBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
But before I actually assign it to my BitMap var over there I need to scale it down to a reasonable size for a phone.
Any help with understanding what is going on here better is appreciated.
getBitmap() is a weak convenience method. Its body is a whopping four lines of code:
public static final Bitmap getBitmap(ContentResolver cr, Uri url)
throws FileNotFoundException, IOException {
InputStream input = cr.openInputStream(url);
Bitmap bitmap = BitmapFactory.decodeStream(input);
input.close();
return bitmap;
}
This is why I don't bother teaching people about it.
IMHO, the best solution is for you to use one of the many image-loading libraries available for Android, such as Picasso. Most of the good ones can load from a Uri and handle your resizing as part of the operation, doing the heavy lifting on a background thread.
If, for whatever reason, you want to do all that work yourself, call BitmapFactory.decodeStream() with a BitmapFactory.Options object. In particular, set inSampleSize to indicate that you want the image to be resampled as part of reading it, so you wind up with a smaller Bitmap taking up less heap space.
I'm developing application for my android tablet that using many images.
in my activity, I use effect splash that show image (3840 x 2108 70 KB) for the opening theme.
I use another background image (3840 x 2108 69 KB).
but, when I test it on my tablet, this application's cache reached 80 MB!
For your information, I load the image from my xml file.
Can anyone help me to reduce it?
Is it wrong to load image from xml file?
Is it the size of my images that cause this problem?
//UPDATE
at the end, i didn't found a really good way to my question. I'm using xml (I put at dawable) file to replace my big size image, and this method really reduce the cache alot. My conclusion is avoid using big image, instead, just replace the color image using color.
The advantage to use color is "faste to load", it reduce lag of my application.
Android default color model is ARGB_8888. It takes 4 byte for 1 pixel. So splash and background bitmap images in memory takes 3840*2108*4*2 = 61.76MB. You could resize the images for different device dpi and put them in proper drawable folder. For example, drawable-hdpi is suitable for 240 dpi, drawable-xxhdpi is suitable for 480 dpi.
In addition, you could manually load the images with java code. The following is a method to resolve the image safely:
protected Bitmap getBitmapSafely(Resources res, int id, int sampleSize) {
// res = youractivity.getResources, id = R.drawable.yourimageid
Bitmap bitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
options.inSampleSize = sampleSize;
try {
bitmap = BitmapFactory.decodeResource(res,
id, options);
} catch (OutOfMemoryError oom) {
Log.w("ImageView", "OOM with sampleSize " + sampleSize, oom);
System.gc();
bitmap = getBitmapSafely(res, id, sampleSize + 1);
}
return bitmap;
}
Your could use this method with sampleSize = 1 at first time. If there is not enough memory, it will catch OOM and increase the sampleSize until the image can be resolved.
I have dug insanely deep into this topic and found out a lot of options that makes the bitmap loading easier. But what I want to achieve is a lil far-fetched. I have referred this [video] which helps in loading the bitmaps efficiently. My question is unique cause I am able to load n number of bitmap images without any glitches but the problem is that it loads the SAME image1.
CODE :
for(int i=0;i<10;i++)
{
...
in = httpConn.getInputStream();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inJustDecodeBounds = false;
options.inBitmap = image;
options.inSampleSize = 1;
image = BitmapFactory.decodeStream(in,null,options);
item = new RowItem(image, product_name, cost,product_id, dream_status,username); --> item is an object of holder class which has get and set methods
rowItems.add(item); --> this is an arraylist object of type holder class
}
Here I have a loop that loads 10 images from WebService, and I am setting it in a adapter at onPostExecute of an async task. When I loop through the 10 images, what happens to me is that, only the last image(10th image) gets set in the view and it gets repeated for all the 10 images. This is due to the following line :
options.inBitmap = image;
which recycles the bitmap. My question here is that, how can I use the inBitmap function and set all the images ? I mean the logic or loop that would let me set not only the 10th image but all the other images. Any help would be highly appreciated guys.I'll be happy to help if you guys have any queries.
NOTE : I am well aware of the fact that inSampleSize should always be set in powers of 2 but setting it to 2 reduces the size of my image and setting it to 1 is what meets my expectation.
I suggest creating a BitmapPool class to smarten up the way you cache and re-use bitmaps. In your example, this pool could start off with a size of 10, and will cache 10 bitmaps. The pool size can grow or shrink depending on the implementation.
you may request a bitmap from this Pool, via getBitmap(), and
Bitmap obtained via getBitmap() call can be used as "inBitmap" while decoding the image
you may return the bitmap back to the pool once you are done using/drawing its contents via returnBitmap()
You can extend the use of BitmapPool to facilitate other bitmap requests in your app.
By following this link, I have written the following code to show a large image bitmap from sdcard.
try {
InputStream lStreamToImage = context.getContentResolver().openInputStream(Uri.parse(imagePath));
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(lStreamToImage, null, options);
options.inSampleSize = 8; //Decrease the size of decoded image
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeStream(lStreamToImage, null, options);
} catch(Exception e){}
image.setImageBitmap(bitmap);
But it is not returning the bitmap(I mean it returns null). In logcat it is showing the below message repeatedly
08-02 17:21:04.389: D/skia(19359): --- SkImageDecoder::Factory returned null
If I will comment the options.inJustDecodeBounds line and rerun it, it works fine but slowly. The developer guide link I provided above says to use inJustDecodeBounds to load bitmaps efficiently.
Please tell me where I am doing wrong.
inJustDecodeBounds does not load bitmaps. That's the point of it. It loads the dimensions of the bitmap without loading the actual bitmap so you can do any pre-processing or checking on the bitmap before you actually load it. This is helpful is you, say, were having memory issues and you needed to check if loading a bitmap would crash you program.
The reason your bitmap might be loading slowly is because it's probably very large and SD cards are very slow.
EDIT:
From the documentation:
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.
Edit 2:
Looking at your code with the example provided by Google, it looks like you are doing relatively the same thing. The reason it's returning null is possibly your InputStream has been modified in the first decoding and thus not starting at the beginning of the bitmap's memory address (they use a resource ID rather than InputStream.
From the code you supplied here, here's what I've figured. You are ALWAYS setting a sample size to 8 regardless of what the first decoding gives you. The reason Google decodes the first time is to figure out what the actual size of the bitmap is versus what they want. They determine that the bitmap is ZxZ dimensions and they want YxY dimensions, so they calculate the samplesize that they should use from the second decoding. You are not doing this. You are simply retrieving the dimensions of the bitmap and not using them. THEN, you set the sample size to a hard-coded 8, swapping it to a hard-coded ARGB_4444 bitmap, then decoding the full bitmap in to memory. In other words, these three lines are not being used:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(lStreamToImage, null, options);
Setting inJustDecodeBounds merely gives you the bitmap's dimensions without putting the bitmap in to memory. It doesn't make it more efficient. It's meant to allow you to load bitmaps in a smaller memory space if they are too big because you can pre-decide what size it should be without decoding the whole thing).
The reason decoding the bitmap is slow might merely be a CPU thing. Depending on the size of your bitmap, you're loading the bitmap from an InputStream from the SDcard which is a slow operation in itself.
I read many discussions about the inSampleSize OutOfMemory dilemma.
Cannot get a good solution so i ask a question about it.
Im currently loading a bitmap with inSampleSize=4.
That will give me a Bitmap with the size 648x388.
Original On disk size is 2592x1592.
Im writing text on 648x388 bitmap and saving it back to disk.
Im writing on the 648x388 because the 2592x1592 give me OutOfMemory .
The way it works is that there can be 1-10 648x388 Bitmaps to be saved in a while loop.
I want to change this loop to save 1-10 2592x1592 Bitmaps.
How can i securely load the 2592x1592?
I don care about the resolution going down 60% or more.
As long as the Bitmap has the same size 2592x1592.
Is there a way to maybe keep the size but make Bitmap thinner,
removing color without making quality bad.
My first thought was going something like this to get the biggest bitmap i could get:
I have not tested this but get a feeling it's a bad way
boolean work = true;
int insample = 2;
BitmapFactory.Options options = new BitmapFactory.Options();
while(work){
try{
options.inSampleSize = insample;
bitmap = BitmapFactory.decodeFile(filePath,options);
work = false;
}catch(Exception e){
insample++;
}
}
any help would be grate.
Image processing requires a lot of memory. you cant use the whole bitmap and just modify it on your phone. use a web service for that. upload, process, download. sorry there is no other way a decoded bitmap just takes a lot of memory.
And by the way you cant catch an outOFMemory Exception. the app just crashes.
There's a hard limit on process size in Android and a 4 mega-pixel image at four bytes a pixel will hit it all by itself (on many devices), without any room for your program.
I think you are going to need to do one of two things: Create a web service to do the image processing on a server/in the cloud; or learn to do your image processing "on-the-fly" by manipulating the data directly instead of using a bitmap.