Android- BitmapFactory.decodeFile makes my app slowly - android

I'm writing app with ActionBar Tabs and ViewPager. I have two tabs and two pages. First page is just Fragmet and second is ListFragment.
In first page i'm inverting infromations about plat like name, interval between water, photo etc. I can add default photo (from resources) and take photo of plant. Then i save photo's data in database like String in two ways: id of image from resources or path to saved photo.
In second page (ListFragment) is ListView with custom adapter and there is the problem.
One row of list contains two TextViews, CheckBox and ImageView.
In method getView of my custom adapter every line works fine, but decoding file to bitmap takes lot of time and it makes my app alowly, even after decoding all photos.
It's my code to set up an image in each list row:
private void setUpImage(int position, ImageView photo)
{
if(plants.get(position).getPhoto().contains("jpg"))
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 10;
Bitmap bitmap = BitmapFactory.decodeFile(plants.get(position).getPhoto(), options);
photo.setImageBitmap(bitmap);
}
else
{
photo.setImageResource(Integer.parseInt(plants.get(position).getPhoto()));
}
}
Do anyone know how to improve speed of decoding and seting image in each list row of my ListView?

First of all! Setting options.inSampleSize = 10; is much greater. Normally, inSampleSize is provided in power of 2. And setting it equal to 2 or 4 is ok.
You can decode your file in background thread or you can use Lazy Loading techniques.
You can get Lazy Loading code here. See this answer.

Related

Loading Bitmap Efficiently in Android

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.

Android ListView showing images results in out of memory

Okay,
I have what I think is an odd problem.
I load photos into a list view as the user scroll (meaning if picked up from disk or online, it takes a little time and they "pop in")
1)
I ensure that I only fetch one image online + resize to 1/3 width at a time (a lock) -- this is to ensure not e.g. 5 threads each are converting a .jpg to bitmap at the same time. (Imagine a user scrolling very fast, it would then be conceivable this could happen.)
2)
All images on disk are only 1/3 width
3)
While the bitmaps are scaled up to fit device width, I call recycle and set bitmaps to null when used in the getView. (I am converting bitmaps to a BitmapDrawable object which the listitem imageview uses in a setImageDrawable call)
4)
I reuse view in getView if not null
5)
I load bitmaps like this:
BitmapFactory.Options o = new BitmapFactory.Options();
o.inPurgeable = false; // I do not use this since I resize/scale down images myself later
o.inInputShareable = false;
o.inPreferredConfig = Config.RGB_565;
res.bitmap = BitmapFactory.decodeStream(is, null, o);
6)
I also clean scrap items
public void onMovedToScrapHeap(View view) {
final TextView description = (TextView)view.findViewById(R.id.listitem_news_content);
description.setText("");
final ImageView image = (ImageView)view.findViewById(R.id.listitem_news_image);
image.setImageBitmap(null);
}
I am testing on a Samsung Galaxy II. Do you guys have any ideas on what more I could try? Since I only max need to show 10 items, I would think it should be possible...
Try using widely used library Universal Image Loader https://github.com/nostra13/Android-Universal-Image-Loader
It is simple and straight forward and you will never have to care about decoding images yourself.
Option two: There's a powerful new API for loading image is available from the team of Square http://square.github.io/picasso/
Try this, it worked for me in case of OutOfMemory...using System.gc()
bitmap = null;
imageView.setImageBitmap(null);
System.gc();

Handling Large Bitmaps in Image Editor

For the program I am currently writing I need a simple image editor. Essentially the user navigates to this editor by simply selecting an image from a gallery. Upon selection the image editor activity is created and should allow the user to perform simple editing actions such as rotation, brightness adjustment, zoom etc.
At the moment I have managed to implement the aforementioned functionality with relative ease. My problem lies in dynamically adding the image in question to the ImageView. As many of you might know; the Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. Thus I am only able to load compressed versions of the bitmap into my ImageView and this presents a rather large problem for me (my program is mainly designed for use on tablets). I have done significant research on this issue and have found that one can essentially split a Bitmap into several smaller bitmaps and place them in several ImageView to create the illusion of one contiguous image using BitmapRegionDecoder(as suggested in this thread). While this has successfully allowed me to display large images I have no idea how I am supposed to implement zooming functionality using multiple instances of ImageView. Is there a relatively simple way of going about doing this?
Have a look at this video from Google I/O where they develop an Advanced gallery app with image editing.
You can download source code for the application here. This is how it opens the activity for image editing:
private OnItemClickListener mPhotoClickListener = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// User clicked on photo, open our viewer
final Intent intent = new Intent(AlbumActivity.this, PhotoActivity.class);
final Uri data = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
intent.setData(data);
startActivity(intent);
}
};
The gallery also implements image editing functionality. The code might be helpful.
Did you try this? options.inJustDecodeBounds should be set to true.
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;
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

How to implement an image gallery (local images)

Currently im making an app to show images from SD card. Basicly you make an album and add pictures to it, be it from camera of the MediaStore picker.
I tried implementing 2 methods:
The standard gallery app with a custom BaseAdapter to return a view
A viewpager with custom PagerAdapter
I dont want to display a grid view, so it should go fullscreen right away. After that i want to disable swipe left and right and only listen for clicks.
Atm both methods work in portrait mode. When i switch over to landscape some images just drop
03-20 12:20:56.515: W/OpenGLRenderer(17398): Bitmap too large to be uploaded into a texture
followed by Out of memory errors. Stack overflow if full with problems about the OOM and the gallery, you should recycle the views to make them work because convertView is always null in the getView from BaseAdapter.
So i used a recycler for the views, i limit it to 2 views and portrait mode worked for method 1 (using the gallery). Landscape still gives me the same problem.
For method 2 (viewflipper) it handles the views by
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
Wich is never called btw... However portrait mode works here. Landscape still crashes.
My method for getting the bitmap:
public static Bitmap getBitmap(Context ctx, int imageId, ImageView target) {
String file = getPath(ctx, imageId);
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, bmOptions);
WindowManager mgr = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
int scaleFactor = 1;
if (mgr != null) {
// Get the dimensions of the View
int targetW = mgr.getDefaultDisplay().getWidth();
int targetH = mgr.getDefaultDisplay().getHeight();
Log.d(TAG, "Image width + height=" + targetW + "," + targetH);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
scaleFactor = Math.min(photoW / targetW, photoH / targetH);
} else {
Log.d(TAG, "Target is null");
}
// Get the dimensions of the bitmap
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
logHeap(ImageHelper.class);
Bitmap bm = BitmapFactory.decodeFile(file, bmOptions);
if (target != null) {
target.setImageBitmap(bm);
}
return bm;
}
Works fine, i know i use the window manager to get a screensize but that is because my ImageView is still size(0,0) when i inflate it. Afterwards i call
imgView.setLayoutParams(new Gallery.LayoutParams(
Gallery.LayoutParams.FILL_PARENT,
Gallery.LayoutParams.FILL_PARENT));
imgView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
Nothing seems to work...
Please note that i dont use drawables or any other resources included in the APK.
This gallery should be able to load pictures from SD card or from camera in whatever quality they were taken. Obvously the gallery should be able to handle as much images as there are in the directory.
Could someone please help me out with the following questions?
Is there any way to make the default Gallery go fullscreen right away and block out the grid view? This way i only need an adapter to provide images instead of making my own views. (maybe this solves the OOM crashes)
Is my Bitmap decoding function ok? Do i need to built in some hacks to catch the landscape changes?
Whats the best way to make the kind of gallery i need, using a viewpager or the gallery?
Does anyone have some sample code of a fullscreen gallery that doesnt crash?
This is an issue i faced a few times in the past. Google actually posted an article about this.
The problem is in the inSampleSize that u use to decode the image. Since different devices have different screens and memory sizes (VM Heap Sizes that may go from 12 to 64 or more Mb) you cant decode the images the same way in all of them. For example, an image in a 320x240 device with a 12Mb Heap Memory should u a given inSampleSize while a 1280x720 64Mb Heap Memory device should user another inSampleSize (a bigger one).
The article i attack shows an efficient way to render the images for a given height and width. Take a special attention to the last code segment, they "pre-open" the file and calculate the inSampleSize for a "full-decode" later on.
I would also like to add this recommendations.
Use the "getBitmap" function in an async way, call a new thread or an asyncTask (this is done because using the SD takes time and this will cause your application to hang, to be slow and give a bad impression on low-mid end devices.
Try to always use the same Bitmap object. Avoid creating multiple "Bitmap bitmap = new Bitmap()". You have to realize that loaded bitmaps are stored in ram and once assigned to a view its "harder" for the garbage collector to get them.
When you have finished using a Bitmap over make it null. This of this, imagine your have 12Mb max heap RAM. your app is using 8Mb now. Garbage collector starts and cant get any more unused RAM. you 10 Bitmaps fast never make them null after assigning the data to the ImageView and somehow you retain their reference. Taken that each bitmap take 500Kb of Ram your app will crash. Always make Bitmaps null after using.
Finally use the DDMS provided in the google platform-tools (you can access it with the eclipse to debug and see your memory usage, you can also force Garbage Collection to see how your app behaves).

display huge Images in Android

I'm intending to display very large Images in Android. My first solution - to supply them as pdf - fails because not every handheld got a pdf-viewer preinstalled, and I don't want to require the users to install one.
So I have a png now (width = 3998px height=2827px) that I want to display. I downloaded this image to test how it would be displayed the gallery. It was quite painful. It seems that the galery renders this picture only once, and if I Zoom in, I cannot read the text at all.
So I wrote a testActivity which simply has an ImageView nested in a LinearLayout. I put the image into the drawable and set it as ImageView's image-source.
Unforunately the app crashes immediatly, due to an "
ERROR/AndroidRuntime(8906): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget"
I didn't expect that ONE single Image can be too large forVM's memory. I played a little bit around, set ImageViews size to 3998 & 2827px , put the Image to sdCard and read it manually with a fileInputStream.
To my big surprise it now shows my image, but if I turn my Nexus S horizontal I get the same OutOfMemoryError as before.
Can somewone point me the main difference between recieving a Bitmap through a FileInputStream or to set it as ImageView's source.
Also I'm not able to scroll comfortable with two parent scrollViews
I searching for a simple solution to display ONE large image at a time with the ability to scroll horizontal and vertical while able to zoom in and out.
here is a sample of the image I want to display
I know it's an old post but I spent a lot of time on this problem, so here's my solution.
I wanted to display a 2000×3000 picture but I got out of memory or the image was too large to be displayed.
To begin, I get the dimensions of the picture:
o = new BitmapFactory.Options();
o.inJustDecodeBounds=true;
pictures = BitmapFactory.decodeStream(new FileInputStream(f), null, o);
Then I cut it up into four parts and displayed them with four ImageViews.
I tried to load the full picture and cut it into four (using BitmapFactory.create(bitmap,int,int,int,int)) but got out of memory again.
So I decided to use some BitMapRegionDecoder:
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
ImageView iv = new ImageView(this);
InputStream istream = null;
try {
istream = this.getContentResolver().openInputStream(Uri.fromFile(f));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
BitmapRegionDecoder decoder = null;
try {
decoder = BitmapRegionDecoder.newInstance(istream, false);
} catch (IOException e) {
e.printStackTrace();
}
int nw = (j*width/k);
int nh = (i*height/k);
Bitmap bMap = decoder.decodeRegion(new Rect(nw,nh, (nw+width/k),(nh+height/k)), null);
iv.setImageBitmap(bMap);
}
}
This worked.
I know its an old question but I used TileView to do exactly this:
https://github.com/moagrius/TileView
Try to use this one:
https://github.com/davemorrissey/subsampling-scale-image-view
A custom image view for Android, designed for photo galleries and
displaying huge images (e.g. maps and building plans) without
OutOfMemoryErrors. Includes pinch to zoom, panning, rotation and
animation support, and allows easy extension so you can add your own
overlays and touch event detection.
You can use this "easy to integerate" source of WorldMap application:
https://github.com/johnnylambada/WorldMap
This uses a huge image of a world map, and uses cache to display a map.
To integerate, I just copied all the java files (5 i guess) and used the surfaceView in my layout file. Then I went through the small OnCreate() method of ImageViewerActivity.java and used the code in my activity (with sligh alteration, depending on my personal use).
This post is a good demo for zooming a picture using multi touch gestures. It uses Matrix to zoom as well as pan a picture.
To handle scaling etc and using full resolution, You can use MapView of OSM (open street map) and provide it with your tiles (instead of the map). Check this: http://www.haakseth.com/?p=30
We have to follow following steps to remove out of memory exception while loading huge images:
1. Read Bitmap Dimensions and Type
2. Load a Scaled down version into memory
Android Developer's Guide defines how we achieve these.
here is the link
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap

Categories

Resources