OutOfMemoryException when showing a listview with videos thumbnail - android

i need to pick multiple videos from gallery, and I've implemented a custom gallery starting from https://github.com/luminousman/MultipleImagePick .
When i'm loading thumbnails in the adapter, it gives me OutOfMemoryException after i starti the gallery Activity twice sequentially.
The code on adapter:
VideoThumbnailImageLoader thumb=
new VideoThumbnailImageLoader(
thumbPath,
MediaStore.Video.Thumbnails.MICRO_KIND);
holder.imgQueue.setImage(thumb,
R.drawable.no_media);
and the VideoThumbnailImageLoader code:
public class VideoThumbnailImageLoader implements SmartImage {
private String videoPath;
private int thumbnailKind;
public VideoThumbnailImageLoader(String videoPath, int thumbnailKind) {
this.videoPath=videoPath;
this.thumbnailKind=thumbnailKind;
}
#Override
public Bitmap getBitmap(Context ctxt) {
return ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Images.Thumbnails.MICRO_KIND);
}
}
I'm using http://loopj.com/android-smart-image-view/ to load video thumbnail.
How can I avoid that?

Set android:largeHeap="true" in your activity proAndroidManifest.xml

Related

How to get the Uri path from a ImageView?

I am trying to create a wallpaper application. All images will come from internet.
Before of set as background, I need to crop the image. And for this, I am using an API named AndroidImageCropper. This API need of a URI object to execute the crop.
How can I get the Uri from ImageView? Because my image is from internet. The image is not on drawable folder. I am confusing. Maybe you guys can help me.
public class MainActivity extends AppCompatActivity {
private NetworkImageView imageView;
private Uri mCropImageUri;
public static final String URL_PHOTO = "http://cdn.wonderfulengineering.com/wp-content/uploads/2016/02/iron-man-wallpaper-42-610x1084.jpg";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (NetworkImageView) findViewById(R.id.image_view);
// Singleton for Volley API, Load image from internet
ImageLoader loader = MySingleton.getInstance(this).getImageLoader();
loader.get(URL_PHOTO, ImageLoader.getImageListener(imageView, R.drawable.temp_picture, android.R.drawable.ic_dialog_alert));
imageView.setImageUrl(URL_PHOTO, loader);
// Put the image on URI object
// #################################
// ### mCropImageUri = <-- ###
// #################################
}
// Action for my button
public void cropImage(View view) {
// API to crop an image
CropImage.activity(mCropImageUri)
.start(this);
}
}
Do you have any suggestion to me?
Thanks.
So you're using Volley? I'm not very familiar with Volley, both just some of my thoughts.
After image is downloaded to Android device, try to find the absolute path of the file and use android.net.Uri.fromFile to get a uri from the image.
Or else, can you use Bitmap object directly, instead of an uri.
OK, after some investigation, I think you have two solutions.
Using volley to download image as file, without using ImageLoader. In this way it's easy to get file uri of the image.
For Android-Image-Cropper, you can use Activity or use View(refer here). You can get the Bitmap object of the image in method onLoadingComplete of ImageLoadingListener. Then use com.theartofdev.edmodo.cropper.CropImageView to crop the image.

Android + Volley: how to get image bitmap using ImageLoader?

I'm trying to get images for list view using Volley Library. I created simple HTTP helper with the following method.
/**
* Processing Image request and gets the image with given URL
*/
public Bitmap makeImageRequest(String url) {
ImageLoader il = new ImageLoader(queue, new BitmapLruCache());
il.get(url, new ImageLoader.ImageListener() {
#Override
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
mBitmap = processImageResponse(response);
}
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(Constants.Global.ERROR, "Error: " + error.getMessage());
mBitmap = null;
}
});
return mBitmap;
}
But problem is that:
new BitmapLruCache()
Method is not recognized.
So i tried to create ImageLoader using the following code which i found on the URL:
http://www.androidhive.info/2014/05/android-working-with-volley-library-1/
ImageLoader imageLoader = AppController.getInstance().getImageLoader();
But in thos code i cannot find out where to get
AppController
Because the method code is triggered from the custom
public class HttpHelperClass
And called from the activity using the:
// Try to load remote image from URL
Bitmap bm = http.makeImageRequest("http://camranger.com/wp-content/uploads/2014/10/Android-Icon.png");
ImageView iv = (ImageView) findViewById(R.id.imageView);
iv.setImageBitmap(bm);
Is it the right approach how to load images and how can i repair my code to make succcessfull request?
Many thanks for any advice.
I think your makeImageRequest method will always return null because it takes some time for the onResponse or onErrorResponse listeners to get called but you return the mBitmap immidately!
If you want to use Volley's ImageLoader you'd better get image inside your activity or ... not from another class like your HttpHelperClass.
Also AppController is a class that extends Application and you should create it yourself. (It's in your AndroidHive link. Section 3. Creating Volley Singleton class)
And also for caching images you should not create a new ImageLoader everytime because in this way the caching gets meaningless. You should get that from your AppController class.
Furthermore I suggest you using Picasso because it's way better that Volley in image loading and a lot easier!
With Picasso you only need to call the following line to load an image from web into an ImageView:
Picasso.with(context).load(urlString).to(imageView);

How to download image using volley and store in cache while image not in use

I am using volley library to download network responses. I know volley download images when it is needed only. But what I want to achieve is to download all the images at a time and store in my cache memory.
So basically I want to download all the images at once and store in cache so if there will no interenet also user can see all the images.
I am able to store images in cache using my own LruBitmapCache class.And to download images I am using following method
public void downloadImage(NetworkImageView view, MyApplication application, String imageUrl, Context ctx) {
NetworkImageView image = view;
ImageLoader loader = new ImageLoader(application.getRequestQueue(), new LruBitmapCache(
LruBitmapCache.getCacheSize(ctx)));
image.setImageUrl(imageUrl, loader);
}
This is working fine in downloading the images and storing in cache. But it is only downloading images those are in my main screen.
To download all the images I tried following method
public void downloadCoverImages(){
int i = 0;
for(ImageData data: GetData._instance.getImageList()){
NetworkImageView iv = new NetworkImageView(BaseActivity.this);
iv.setLayoutParams(new LinearLayout.LayoutParams(300,150));
GetData._instance.downloadImage(iv, (MyApplication) getApplicationContext(),
data.getImages().getSmallImage(),BaseActivity.this);
//Log.e("Download",++i+" "+data.getImages().getSmallImage());
}
}
But it's not to download an image a proper ImageView is required I guess and that also needs to in main screen. So in this case what should I do?
My singleton class as follows:
public enum GetData {
_instance;
private List<Sections> sectionsList = new ArrayList<Sections>();
private List<DealDetails> dealDetailsList = new ArrayList<DealDetails>();
private DealDetails dealDetails;
public List<Sections> getSectionsList() {
return sectionsList;
}
public void setSectionsList(List<Sections> sectionsList) {
this.sectionsList = sectionsList;
}
public List<DealDetails> getDealDetailsList() {
return dealDetailsList;
}
public void setDealList(List<DealDetails> dealDetailsList) {
this.dealDetailsList = dealDetailsList;
}
public DealDetails getDealDetails() {
return dealDetails;
}
public void setDealDetails(DealDetails dealDetails) {
this.dealDetails = dealDetails;
}
public void downloadImage(NetworkImageView view, MyApplication application, String imageUrl, Context ctx) {
NetworkImageView image = view;
ImageLoader loader = new ImageLoader(application.getRequestQueue(), new LruBitmapCache(
LruBitmapCache.getCacheSize(ctx)));
image.setImageUrl(imageUrl, loader);
}
}
Is it possible if I download image without using volley and store in my LRUCache and show it using volley? Any good tutorial for that? Thnaks.
you can also get bitmap of remote image using volley imageloader.. in this way you don't need to have imageview and all
imageLoader.get(data.getImages().getSmallImage(), new ImageLoader.ImageListener() {
#Override
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
}
#Override
public void onErrorResponse(VolleyError error) {
}
});
get the imageloader instance from volley singleton class. in your case you don't need to handle the imagelistener callbacks ..

Caching Images - Bitmap not collected after different bitmap was loaded or ImageView's activity closed

I am trying to implement something that is very similar to UrlImageViewHelper (https://github.com/koush/UrlImageViewHelper) where you can easily using a simple one line of code, load images from a url, and if the image was already downloaded it is loaded from the cache instead. The major difference is that I want the same effect but instead of downloading it from a url, I want to receive the images from my own server using my own client-server communication. Every image on my server can be uniquely identified by a string, and I use this as the id for the image.
My main idea was this: Use an LRU Cache to hold the images, but instead of holding the Bitmaps (that are very large) I want to hold the raw image data binary, so I can use the same image to build bitmaps of different sizes and qualities on demand depending on the specific situation.
This is my implementation so far:
public class ImageHandler {
private static class BitmapCache extends LruCache<String, byte[]>
{
public WigoBitmapCache(int maxSize) {
super(maxSize);
}
#Override
protected int sizeOf(String key, byte[] value) {
return value.length;
}
}
private static class ImageHandlerThread extends Thread
{
/* THIS THREAD WILL DECODE THE IMAGE AND SET THE BITMAP TO THE IMAGEVIEW IN THE BACKGROUND */
Activity activity;
ImageView imageView;
byte[] imageBytes;
public ImageHandlerThread(Activity activity, ImageView imageView, byte[] imageBytes)
{
this.activity=activity;
this.imageView=imageView;
this.imageBytes=imageBytes;
}
public void run() {
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o);
int factor1=o.outHeight/height;
int factor2=o.outWidth/width;
/* height and width are for now constant */
o = null;
o = new BitmapFactory.Options();
if (factor1>factor2)
o.inSampleSize=factor1;
else
o.inSampleSize=factor2;
Bitmap bit = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length,o);
setBitmap(bit);
bit = null;
}
private void setBitmap(final Bitmap bit) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
imageView.setImageBitmap(bit);
}
});
}
}
private static class QueueItem
{ /*USED TO HOLD INFO ABOUT THE IMAGE REQUEST UNTIL THE IMAGE GETS FROM THE SERVER */
String imageName;
Activity activity;
ImageView imageView;
public QueueItem(String imageName, Activity activity, ImageView imageView)
{
this.imageName=imageName;
this.activity = activity;
this.imageView = imageView;
}
}
private BitmapCache cache; // this cache holds the image binaries
private ArrayList<QueueItem> queue; // this queue holds the info about the request, until the server sends the image
public ImageHandler(int maxSize)
{
cache=new BitmapCache(maxSize);
queue = new ArrayList<QueueItem>();
}
public synchronized void setBitmap(Activity activity, ImageView imageView, String imageName)
{
byte[] imageBytes = cache.get(imageName);
if (imageBytes==null)
{
QueueItem item = new QueueItem(imageName, activity, imageView);
queue.add(item);
/* HERE IS THE CODE TO RETRIEVE THE IMAGE BINARY FROM MY SERVER, THIS CODE WORKS FINE, SO THERE IS NO REASON TO BOHER YOU WITH IT */
}
else
{
ImageHandlerThread thread = new ImageHandlerThread(activity, imageView, imageBytes);
thread.start();
}
}
public synchronized void insert (String imageName, byte[] imageBytes)
{
/* THIS METHOD IS THE CALLBACK THAT IS CALLED WHEN THE IMAGE BINARY IS RECEIVED FROM THE SERVER */
cache.put(imageName, imageBytes);
for (QueueItem item: queue)
{
if (item.imageName.equals(imageName))
{
ImageHandlerThread thread = new ImageHandlerThread(item.activity, item.imageView, imageBytes);
thread.start();
queue.remove(item);
}
}
}
}
Basically, the main method here is setBitmap(), it gets the activity, the imageView that needs the bitmap, and the name of the image name. If the image is already in the cache, a new thread is started to decode the bytes into the proper size bitmap and set the bitmap to the imageView. If the image is not present in the cache, the request is put in a queue until the image is received, the image is retrieved from the server and then the same thread as before is started.
All this works absolutely fine, the problem is that when the imageView is set another bitmap for the image or even when the activity is destroyed, the bitmap is still resident in memory and is not collected by the GC.
At first I though that it is because I was keeping a reference to the activity, and that reference keeps the activity alive, but it seems not to be the case, my reference to an activity is very short lived, and once the image arrives from the server this reference is cleared.
I am running out of memory fast with this implementation, and I have no idea why or what to do to fix it. The bitmaps I create are not collected although I keep no references to them. Could this be an artifact of the way I decode the images? or do the threads keep references that are not collected properly? Anyone has any ideas?
Ok, so I misunderstood the problem, what was happening is that the GC was not collecting the finished thread objects because I was running this in debug mode, and not in run mode. When I ran this in run mode, the memory usage of my app did not go above 8MB at all, while when it was in debug mode I got to the 25MB+ area.
Conclusion: Do not trust the GC and memory usage info in debug mode, especially if you have many short term threads running.

SkImageDecoder::factory returned null

i am trying to display an image from net..and i am using ignition library for RemoteImageView..
this is the code..
public class images extends Activity{
public String a,b,c,d;
public java.lang.String url;
RemoteImageView iv;
Bitmap bitmap;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
a= getIntent().getExtras().getString("s1");
b = getIntent().getExtras().getString("s2");
c = getIntent().getExtras().getString("s3");
d = getIntent().getExtras().getString("s4");
setContentView(R.layout.ignition);
iv=(RemoteImageView)findViewById(R.id.image1);
}
public void p(View v) throws MalformedURLException{
String u="http://www.infrabazaar.com/"+a;//<--------(1)
iv.setImageUrl(u);
iv.loadImage();
}}
the images should be displayed based on the info sent from the previous class...
if i give a complete link of the image like "http://www.infrabazaar.com/machinary-client-images/1315201358_0.JPG"... iam able display that image on the screen.. but when i am passing the link as in line (1).. it is showing factory returned null message...can any one tell me what can resolve the problem?
This RemoteImageView solves much of the "Factory Returned null " problem... now i get very few times this error... but once i load other image and then try reloading the image for which i got the error it loads properly..

Categories

Resources