I'm loading a 95KB image, dimensions 1024x683 using Universal Image Loader. When I'm on wireless, the image loads just fine. However, if I turn off wireless and use the phone's network, it downloads the image at 305x203.
This is my config:
// setup the image async loader
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.cacheInMemory()
.cacheOnDisc()
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.defaultDisplayImageOptions(defaultOptions)
.build();
ImageLoader.getInstance().init(config);
This is the download:
ImageLoader.getInstance().displayImage(imageUrl, imageView, new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
super.onLoadingComplete(imageUri, view, loadedImage);
android.util.Log.v("image size", String.valueOf(loadedImage.getWidth())+" x "+String.valueOf(loadedImage.getHeight()));
}
});
I've tried removing cacheInMemory. I've tried using loadImage and specifying a target size, but it still downloaded at the smaller size. I tried changing the image scale type, using NONE and EXACTLY, no change.
I feel like I'm missing something obvious, but I can't figure it out.
Dunno exactly what the UniversalImageLoader actually does, but maybe it is responsible. You can find out by downloading the image with a normal AndroidHttpClient connection with both connection types (WiFi and mobile) and then comparing their actual size.
This phenomenon can also happen due to a reformatting proxy of your network operator, that detects your mobile device's user agent and scales down the image without your knowledge or request. I know this sounds odd, but those things happen. You can find out of this is the case, but trying a different provider (change sim cards) or by trying to change the settings of your http user-agent (pretend to be a full blown desktop firefox).
Good luck!
Related
This question already has answers here:
How to load an ImageView by URL in Android?
(23 answers)
Closed 9 years ago.
I have Imageview and a link to the picture on the Internet. I set this picture to the ImageView like this,
public ImageView iv;
iv = (ImageView) findViewById(R.id.imageView);
String img = "https://www.google.com/images/srpr/logo11w.png";
iv.setImageDrawable(Drawable.createFromPath(img));
What I want to do is download a picture from the internet to my android application and apply it to an ImageView. I want to make it as easy as possible.
helped me
String img_url= //url of the image
URL url=new URL(img_url);
Bitmap bmp;
bmp=BitmapFactory.decodeStream(url.openConnection().getInputStream());
ImageView iv=(ImageView)findviewById(R.id.imageview);
iv.setImageBitmap(bmp);
There many libs to do this, my favourite is Picasso.
Here an example of usage:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
give it a try :)
This method create a Drawable from file path name.
Check this answer.
There are many libraries available on doing this, I recommend using a library, because a they have many extra options availble.
Take Universal Image Loader
Features
Multithread image loading
Possibility of wide tuning ImageLoader's configuration (thread executors, downloader, decoder, memory and disc cache, display image options, and others)
Possibility of image caching in memory and/or on device's file system (or SD card)
Possibility to "listen" loading process
Possibility to customize every display image call with separated options
Widget support
Possibility to show an custom Image on loading, error, etc.
You have to set the options one time using:
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisc(true)
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.defaultDisplayImageOptions(defaultOptions)
.build();
ImageLoader.getInstance().init(config);
Then, lateron you can use this anywhere in your code:
ImageView iv = (ImageView) findViewById(R.id.imageView);
String str = "http://google.com/img.jpg";
ImageLoader.getInstance().displayImage(str, iv);
Ofcourse there are many other libraries you can use like picasso, Smart Image View, Url Image View and many others.
I am testing upgrading to use Android Universal Image Loader 1.9.0. I have tested this on Android 4.2. I've come across a problem where I am downloading and caching images in an intent service to be run on a background thread to not interfere with the user. However, UIL is complaining that I am not loading these images on the main thread. I don't want to load these images on the main thread, I just want to be able to cache them on disc in the background so that they don't need to be downloaded when the user actually views the specified images. Is there another way to pre-cache the images on a background thread besides ImageLoader.loadImage? If not, how do I allow pre-caching on disc on a thread that isn't the main thread? All of this code is being run in an IntentService.
ImageLoaderConfiguration:
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
getApplicationContext())
.threadPriority(Thread.MAX_PRIORITY)
.memoryCacheSize(memoryCacheSize)
.denyCacheImageMultipleSizesInMemory()
.threadPoolSize(5)
.discCacheFileNameGenerator(new MyFileNameGenerator())
.tasksProcessingOrder(QueueProcessingType.LIFO)
.build();
DisplayImageOptions:
DisplayImageOptions options = new DisplayImageOptions.Builder().cacheOnDisc()
.imageScaleType(ImageScaleType.NONE).build();
Load image code:
imageLoader.loadImage(imageURI, options,
new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(String imageUri, View view,
Bitmap loadedImage)
{
loadNext(); // gives a notification update and loads next image URI in queue
}
#Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason)
{
loadNext(); // gives a notification update and loads next image URI in queue
}
});
Actually UIL doesn't provide methods for preloading images, i.e. just to add to disc cache. It always returns decoded Bitmap.
But in your case you can use loadImageSync(...). I think it's more appropriate for you.
After diving into UIL's code, I figured out a solution. Not sure it is the best one but may help someone out in the future. If you set your own handler in the DisplayImageOptions, it skips the check to make sure the handler is on the main thread:
DisplayImageOptions options = new DisplayImageOptions.Builder().cacheOnDisc()
.imageScaleType(ImageScaleType.NONE)
.handler(new Handler()) // added this line
.build();
I have a problem using the Universal Image Loader Library.
Unfortunately, the Library causes huge memory usage of my application.
I have a ScrollView (there are tons of reasons why I am using a ScrollView instead of a ListView, most of them have to do with custom insertion and item selection animations) holding about 20 custom Views.
Each of those custom views consists of some TextViews as well as an ImageView.
And now here is the thing:
The Images dispalyed in the ImageViews are downloaded from the Internet and all have around 100-150kb (dimension 640 x 320) each. If I download the Images using the UniversalImageLoader my app crashes with an OutOfMemoryException because it uses around 80Mb of memory.
If I do not download the Images, and just put in a Hard-Coded Image with the size of 1200kb (dimension 1920 x 1080) per custom view, my app only consumes around 40Mb of memory.
What am I doing wrong using the UniversalImageLoader when downloading ten times smaller Images causes my app to use up twice as much memory?
I disabled all caching mechanisms but the problem still persists.
Here is my UniversalImageLoader setup:
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(c)
.build();
ImageLoader.getInstance().init(config);
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.loading)
.showImageForEmptyUri(R.drawable.loading)
.showImageOnFail(R.drawable.loading)
.cacheInMemory(false)
.cacheOnDisc(false)
.imageScaleType(ImageScaleType.IN_SAMPLE_INT) // default
.build();
And in code, I call it like this:
ImageLoader im = ImageLoader.getInstance();
im.displayImage("myurl", myimageview, options);
What am I doing wrong? Why is the UniversalImageLoader using up so much memory?
For all the other people out there having the same issues:
I managed to minimize my Memory usage and get rid of the OutOfMemoryException by following these guidelines:
https://github.com/nostra13/Android-Universal-Image-Loader#useful-info
The most important part for me was to reduce the ThreadPoolSize down to 2. I could not feel any performance changes after setting it down.
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(c)
.threadPoolSize(2)
.build();
DisplayImageOptions options = new DisplayImageOptions.Builder()
// other options
.bitmapConfig(Bitmap.Config.RGB_565)
.imageScaleType(ImageScaleType.EXACTLY)
// other options
.build();
This reduced my applications total memory consumption by about 35%.
I can't find in any really credible source explaining what LazyList is. Anyone?
Lazy List is lazy loading of images from sd-card or from server using urls. It is like on demand loading of images.
Images can be cached to a local sd-card or your phone's memory. URL is considered the key. If the key is present in the sd-card, images get displayed from sd-card, otherwise it downloads the image from the server and caches it to a location of your choice. You can set a cache limit. You can also choose your own location to cache images. Cache can also be cleared.
Instead of the user waiting to download large images and then displaying them, lazy list loads images on demand. Since images are cached, you can display images offline.
https://github.com/thest1/LazyList. Lazy List
In your getview
imageLoader.DisplayImage(imageurl, imageview);
ImageLoader Display method
public void DisplayImage(String url, ImageView imageView) //url and imageview as parameters
{
imageViews.put(imageView, url);
Bitmap bitmap=memoryCache.get(url); //get image from cache using url as key
if(bitmap!=null) //if image exists
imageView.setImageBitmap(bitmap); //display iamge
else //downlaod image and dispaly. add to cache.
{
queuePhoto(url, imageView);
imageView.setImageResource(stub_id);
}
}
An alternative to Lazy List is Universal Image Loader
https://github.com/nostra13/Android-Universal-Image-Loader. It is based on Lazy List (it works on the same principle), but it has lot of other configurations. I would prefer to use Universal Image Loader because it gives you more configuration options. It can display an error image if a download failed. It can display images with rounded corners. It can cache on disc or memory. It can compress an image.
In your custom adapter constructor
File cacheDir = StorageUtils.getOwnCacheDirectory(a, "your folder");
// Get singletone instance of ImageLoader
imageLoader = ImageLoader.getInstance();
// Create configuration for ImageLoader (all options are optional)
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(a)
// You can pass your own memory cache implementation
.discCache(new UnlimitedDiscCache(cacheDir)) // You can pass your own disc cache implementation
.discCacheFileNameGenerator(new HashCodeFileNameGenerator())
.enableLogging()
.build();
// Initialize ImageLoader with created configuration. Do it once.
imageLoader.init(config);
options = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.stub_id)//display stub image
.cacheInMemory()
.cacheOnDisc()
.displayer(new RoundedBitmapDisplayer(20))
.build();
In your getView()
ImageView image=(ImageView)vi.findViewById(R.id.imageview);
imageLoader.displayImage(imageurl, image,options);//provide imageurl, imageview and options
You can configure Universal Image Loader with other options to suit your needs.
Along with LazyList/Universal Image Loader you can view this website for smooth scrolling and performance.
http://developer.android.com/training/improving-layouts/smooth-scrolling.html.
AFAIK, I'll explain you with the example
If you list contain lot of images with Text, it will take some time for your list to load because you need to download images and you need to populate them in the list. Suppose if your list contains 100 images It will take lot of time to download each image and to show it the listitem. To make the user wait until the images loads is not user friendly.
so What we need to do. At this point of time lazy list comes into picture. It is the idea that let the images be loaded in background and show text mean while.
Everybody know that listview recycle its views for every view. i.e if your listview contains 40 elemtns then listview won't allocate memory for 40 items instead it allocate memory for the visible items, i.e say you can see only 10 items at a time. so listview will allocate 10 items meemory.
So When ever you scroll the view, then the view will refresh. because of the you'll lose your reference to images and you need to download them agian. in order to avoid that, caching comes into picture.
This example is based on my knowledge in listview, I am not saying this is only correct. There might be wrong in the answer, if any body find feel free to inform me.
I think this is the other way around. AFAIK, Lazy Loading is the definition, where you actually load the data only when you need it, and it's a good design practice.
So I believe the same applies for this, only this time it's being referring to the List View.
If I'm wrong, please correct me.
The best example of lazy list is facebook notifications,messages,requests. when you scroll then data will be load.
I have a Custom AdapterView (sort of) in which I lazy load images. To do it, I use the awesome aquery library.
Short story: I would like to cache (memcache and filecache) the downsampled version of the file. It makes it quicker to add to my adapter - when the image is small I have no lags when scrolling my AdapterView. When the image is big, even if I use downsampling it lags a bit. I found out, that aquery stores the full version of image and downsamples it every time I call aq.image(...). How to cache the resized version, not the original one?
Long story:
My AdapterView relies heavily on images. These images are rather big, and when adapter items gets instantiated it takes some time to downsample it and then add to the list. So I thought it would be nice, to instantiate items with a lo-res photo when scrolling, and only load the hi-res version when the scrolling stops. It works like a charm, when I use two separate image urls (one for thumnbail and another for the original image). But the API I work with is quite limited, so I won't have the thumbnail images' urls. I have to async download the big version, downsample it, save both big and small version and then use whichever I need. And here the "short story" begins.
I just released an open source library called droidQuery which is a full port of jQuery to Android. It is much simpler to use than AQuery, and provides a lot more configurations. To download an image and set the output size, and cache the small image (on a per-session/every ten minute basis), you can use the following code:
final ImageView image = (ImageView) findViewById(R.id.myImage);
$.ajax(new AjaxOptions(url).type("GET")
.dataType("image")
.imageHeight(200)
.imageWidth(200)
.context(this)
.cache(true)
.cacheTimeout(600000)
.success(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
$.with(image).val((Bitmap) params[0]);
}
})
.error(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
droidQuery.toast("could not set image", Toast.LENGTH_SHORT);
}
}));
I also used AQuery library in the past, but after encountering some problems with limited configuration and weird progresbar visibility issue, I moved to Android-Universal-Image Loader
https://github.com/nostra13/Android-Universal-Image-Loader it gives you your needed feature as well as plenty other useful configuration options.
Just read this site from top to bottom - and you should be able to run it in a minute.
In your case most interesting lines are
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.memoryCacheExtraOptions(480, 800) // default = device screen dimensions
.discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75)
.discCache(new UnlimitedDiscCache(cacheDir)) // default
.discCacheSize(50 * 1024 * 1024)
.discCacheFileCount(100)
You can also change cached file names.