When to recycle bitmap in android project? - java

I have successfully implemented lazy loading of list images and list items in Android listview. I am using Android 4.0+ and Java 7.
The algorithm i followed is:
List data(including image URL) is downloaded from internet as and when user scrolls the list.
When scroll state is idle, list images are loaded.
In the background thread, images are first checked for in the cache. If not present in cache, they are downloaded and stored into the cache.
Lastly image is set to imageview in the listview and adapter is notified.
The only problem is I am not clear about when to recycle bitmaps. I tried using bitmap.recyle() at many places but I got the following error:
java.lang.IllegalArgumentException: Cannot draw recycled bitmap
It is not possible to add that vast code over here. Also there are some privacy issues. Can someone please help me about this?
EDIT
My application size increases from 727 KB (at the time of installation) to 14 MB.
After I recycle my bitmaps, in getView() of adapter I get "cannot generate texture from bitmap ".
Can anyone suggest how to get rid of it?

Recycling a bitmap renders it unusable. Only recycle when you're completely done with it. In your case, that means after it's been evicted from the cache. You'll also want to make sure that none of your existing views reference it.

As of ICS the need to recycle isn't necessary. There are a few instance where you would want to but considering most listview implementations it probably won't be necessary.
You can check out this video by Chet Hasse for more info on reusing bitmaps which would be better if they are the same size. DevBytes: Bitmap Allocation

Bitmap recycling should be performed differently in different versions of Android. It is best to implement in a way that covers the majority of versions.
As others here said, recycle() renders your bitmap unusable, recycle() is meant to be used once you are finished with the bitmap and would like to induce a garbage collection. I think you should use it on your activity onPause()/onStop().
See here for more information:
Managing Bitmap Memory

Related

Scrollable gallery in android, deallocate memory

So, I currently have a recycler view with gridlayoutmanager which through a listener loads more bitmaps asynchronously. Problem is, when I scroll too far down, program crashes due to the fact that there's an ArrayList holding 1000+ bitmaps.
I tried to compress bitmaps with an inSampleSize of 8, and to load from the thumbnails, so my guess it that problem resides in the array holding so many bitmaps.
My question is, is there any way I can, say after 200 bitmaps start to delete them from the array without breaking the scroll system? After deleting them, how would I place the Cursor to start getting bitmaps again? I can add a function that after 200 bitmaps gets called, but I need some hints in order to implement it.
I guess this is a very code-independent question, but in case any code is needed you can have a look at this repository.
Thanks.

OutOfMemoryError Android Issue

There's three screens. The first is the main screen, the second is a filler screen and the third contains a screen with 4 buttons.
Main screen contains one button that leads to the 2nd screen, 2nd screen contains another button that leads to the 3rd screen.
Images are stored in drawable-hdpi.
The outofmemoryerror occurs when I press the button in the 2nd screen, specifically the android.app.Activity.setContentView in the onCreate on the 3rd screen.
The app works fine if it's only going from the 1st to the 3rd screen but we need to add some screens in between the 1st and 3rd screen.
Here's the logcat:
Edit: I have a S4 (International) but it works fine on a Nexus 5.
It looks like you are loading a bitmap into memory. In an android app you only have about 16 megabytes of ram available, so you can run out of ram very quickly, and an outOfMemoryError will occur.
You can fix this by using the resource id of the image instead of a Bitmap object. For example, use:
setContentView(R.layout.view_id);
where view_id is the id of the view you want displayed.
The use of images inside your activities can lead to occasional OutOfMemoryError, if you don't follow some guidelines.
First of all, take extreme attention when declaring, initializing and using Bitmaps inside you code. These objects are managed by the system in a special way, this is a good place to start if you want to use them efficiently.
Anyway, since you didn't post any code that show the use of Bitmaps, I focused the attention to a single line of your question:
Images are stored in drawable-hdpi.
Are the images stored ONLY in such directory? Well, this is a bad practice and it's a source of memory errors ;)
When you ask Android to initialize a particular Activity, all the images declared inside its XML are loaded from a particular drawable-**** folder, depending on the screen size of the current device.
For example, a mdpi device will start to look inside the drawable-mdpi for the image named img. If it's not found, then it looks with a cascade behaviour inside all of the other drawable folders.
The problem is here: if the img is found in a different folder than drawable-mdpi, first it's scaled by the system to match the scaling factor for mdpi. Hence, another copy of the Bitmap is created.
Since all your images are inside a single, high resolution folder, the scaling operation will be executed by every non-hdpi device that will run your application. This is not good at all (here some docs).
The solution is to create different scaled versions of the same image and store them in multiple folders, like: drawable-ldpi, drawable-mdpi, drawable-hdpi, drawable-xhdpi
There is a convenient tool that does the dirty job: 9 Patch Resizer

How to set an array list to image view present inside a listview

I have a listview which contains ImageView i. Now I have an array list which contains URLS inside it like www.abc.jpg, www.def.jpg and so on. Now I want to insert these URLs as the source for the image view. Is it possible.?
ImageView doesn't have any API that allows setting of urls that will be downloaded later on. You need to separately from the ImageView setup an asynchronous task that will download this image from the url, convert it to a Bitmap and then set it on ImageView with setImageBitmap(Bitmap).
As noted, you're doing network I/O in the main thread. The stack trace identifies it as happening in onPostExecute. In there, I see this code:
BitmapFactory.decodeStream(newurl.openConnection() .getInputStream()
That certainly looks like network I/O to me.
What I'm wondering is, you've got this lovely worker thread already, but you're doing a lot of work in onPostExecute() (main thread). To prevent janky UI, I suggest you move as much of that computation into doInBackgroud() as possible.

Displaying an image from the internet with android

I am writing on an android app, and my current task is to load an image from a URL and display it in an ImageView.
What i did so far: I managed to download the image and save it as a bitmap. Now when i want to add it to an intent via
intentRecord.putExtra("Data",(DownloadDataImage) result);
where result is my bitmap image, i get an error because a bitmap is not serializable, and .putExtra() requires a serializable input.
Do you guys know any workaround for me? I don't know how to circumvent my problem in an appropriate way.
Is there a way of adding an image to an imageView without using a Bitmap, and instead using another serializable type? Or is there a smooth way of making my bitmap serializable? I know this is possible, but i am not quite sure how to do this.
Thx a lot for your help!
I suggest you to try picasso to do the hard work of handling/caching images.
Once you have the jar in your workspace, you just need one line of code
Picasso.with(context).load(image_url).into(imageView);
Because there is an upper bound to the size of what can be put in Intent extras, you should look into another way to get the image into your ImageView.
At a very high level the steps of this could be:
IntentService downloads image and stores it somewhere that's globally accessible (in-memory cache or on disk).
After download has completed and service has saved the image somewhere, it sends a broadcast to let BroadcastReceivers in your app know that the image is now available.
A BroadcastReceiver in the activity or fragment that is hosting your ImageView would then retrieve the image from the stored location and place it inside the ImageView (if from disk then remember to do this retrieval off the main thread).
As other answerers have mentioned, there are frameworks that do a lot of this boilerplate work. Picasso, as suggested by droidx, is a great solution that's easy to implement and would probably be your best bet.
you can use external library like Universal Image Loader and you won't have to worry about cache management and other things...

GridView loads slow for large image resources

I've been learning android programming for some days. I am creating an ebook application which reads images from the drawable folder. I've successfully implemented the pageviewer activity which loads bitmaps using asyncTask in background and shows a text "loading..." until loading is completed.
I wanted to show a pagelist in another activity using gridview so that user can scroll through a grid of pages and select any. I followed the android gridview tutorial and wasnt much problem. But since i have about 50 images in drawable and it seems gridview adapter shows the grid once all images are croped and placed in grid. It takes a lot of time to show the grid and its quite slow on scroll.
I was wondering if there was a better way to show the grid, asynchronously, like show the first item and then the 2nd and so on, instead of waiting for a long time and displaying the grid. I saw some topics like lazy load which seems similar to what i want, but they all show image from web, it was confusing. Hope i can get some sugestions, or if there is any other way.
Have you tried Fedor's Image Lazy Loader?
Here is the link: Lazy load of images in ListView ,
I know you want to implement it for GridView, but still you can refer the ImageLoader class given in the example code.
Update:
You can even try this example Lazy Loading GridView. I haven't tried it, but as i found it, i thought it may be of your help.
The images you show are probably a bit too large to be used with GridView in their current form.
I guess you need the GridView to display thumbnails, so one possible approach would be to store a thumbnail sized copy of every page you have, and use those in the Grid.
You can also try switching hardware acceleration on in the manifest, that might help you with the scrolling once the images are small enough to load them faster. But afaik hw acceleration is only available in 3.0 and up.

Categories

Resources