save and laod image using universal image loader - android

Updated
So as suggested earlier, i used Universal image loader. But i am getting some error.
**This is the first time i am playing around with this kind of stuff.
Below are my codes :
Here is the code to save bitmap to internal storage using async:
Uri uri = Crop.getOutput(result);
try {
bmp = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
finally {
new saveDpToDisk().execute(bmp);
}
class saveDpToDisk extends AsyncTask{
#Override
protected Object doInBackground(Object[] params) {
try {
fos = openFileOutput("ProPic", Context.MODE_PRIVATE);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
bmp.compress(Bitmap.CompressFormat.JPEG, 60, fos);
return bmp;
}
}
and here is code to load image from storage using UIL:
#Override
protected Object doInBackground(Object[] params) {
FileInputStream fis;
try {
fis = openFileInput("ProPic");
String uri = String.valueOf(fis);
DisplayImageOptions options = new DisplayImageOptions.Builder().cacheOnDisk(true).build();
ImageLoader loader = ImageLoader.getInstance();
loader.displayImage(uri, pro_pic, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return pro_pic;
}
}
And this is the error I am getting (app doesnt force close, error just appears in logcat
UIL doesn't support scheme(protocol) by default [java.io.FileInputStream#42987180]. You should implement this support yourself (BaseImageDownloader.getStreamFromOtherSource(...))
java.lang.UnsupportedOperationException: UIL doesn't support scheme(protocol) by default [java.io.FileInputStream#42987180]. You should implement this support yourself (BaseImageDownloader.getStreamFromOtherSource(...))
at com.nostra13.universalimageloader.core.download.BaseImageDownloader.getStreamFromOtherSource(BaseImageDownloader.java:235)
at com.nostra13.universalimageloader.core.download.BaseImageDownloader.getStream(BaseImageDownloader.java:97)
at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.downloadImage(LoadAndDisplayImageTask.java:290)
at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryCacheImageOnDisk(LoadAndDisplayImageTask.java:273)
at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryLoadBitmap(LoadAndDisplayImageTask.java:229)
at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.run(LoadAndDisplayImageTask.java:135)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
________x_____________________x___________________________x_______________________
Original Question
My app has to load only one image (which user can select from gallery to set as his dp for that app).
So, What I did is I saved the selected pic to storage using FileOutputStream and then load the pic using FileInputStream in activity's onResume method.
But, what happens is that when the selected pic is too large, the app starts up too slowly (takes time to inflate view) and logcat shows memory heap of 30-60 MB.
So, i thought of storing the image in cache and load but dont exactly find a way to do so.
Shall i use picasso? If yes, how to use it for saving and laoding from cache.
Or are there any other ways to achieve what i need?

If you read this post on G+ by Koush you will get clear solutions for your confusions, I have put the summery of that, in that Android-Universal-Image-Loader is the winner for your requirement!
Picasso has the nicest image API if you are using network!
UrlImageViewHelper + AndroidAsync is the fastest. Playing with these
other two great libraries have really highlighted that the image API
is quite dated, however.
Volley is slick; I really enjoy their pluggable backend transports,
and may end up dropping AndroidAsync in there. The request priority
and cancellation management is great(if you are using network)
Android-Universal-Image-Loader is the most popular one out there
currently. Highly customizable.
This project aims to provide a reusable instrument for asynchronous
image loading, caching and displaying. It is originally based on Fedor
Vlasov's project and has been vastly refactored and improved since
then.
Considering all this Android-Universal-Image-Loader suites your requirement (Loading the images are on disk locally)!

Related

download images faster and more efficently

In my app, i repeat an AysnceTask that downloads images from my AWS bucket but they take a little bit to download (1/2 seconds usually) and when I am downloading 10 images it adds up and makes the user experience worse.
My question is: is there a faster way to download images from AWS S3?
Android code:
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
String PhotoURL = "https://s3.amazonaws.com/bucket/Images/" + productForImages;
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(PhotoURL).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
productColumn = 5;
productImages[productRow][productColumn] = result;
}
}
Using different services (like AWS), a GitHub, or another library to speed up downloading is possible!
Try the Glide library recommended by google.
It have more features compared to Picasso library.
Add this dependency in your gradle
compile 'com.github.bumptech.glide:glide:3.5.2'
Load your image using following code
Glide.with(context)
.load("//inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg")
.into(yourImageView);
Reference - https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
Use Picasso - Its a easy to use library by
Step 1: Add dependency in gradle
compile 'com.squareup.picasso:picasso:2.5.2'
Step 2: Use in activity
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Picasso handles all the heavy lifting in the background. It also caches the images for faster image retrieval in the future. Also, Picasso does parallel downloads by default.
If you want to download images faster and more efficiently, then there are methods like multiple connections to download a file (Too much overhead for small files though).
However, the main bottleneck is the users' internet bandwidth. I guess your current implementation is downloading those images every time open your app. This is not efficient. What you can do is that caching the images and checking for update.
For example, when you open your app:
Load the cached images` (If it is fresh install, then there should also be cached images in your app package)
check for image update at the background
If there is an update, download them
When you finish downloading, update your cache and replace the loaded images if needed.
Use multi threaded downloads: You can make Asynctask's run in parallel with myTask.execute(AsyncTask.THREAD_POOL_EXECUTOR). This allows more downloads in same time.
Make server content delivery faster: Add Amazon cloudfront (a CDN) in front of S3. This speeds up downloads for users.
First stream downloading files to a disk cache, then decode into bitmaps of only required resolution. This saves a lot of RAM if you need not show images at full size. Since images are cached, repeated requests for same image will not use network resources.
For #1 and #3, simply use Fresco

Using uri (android.net.uri) as a link to get image from internet and put it in a ImageView

I have a item object, containing a Uri variable called image. something like this
http://icons.iconarchive.com/icons/designcontest/vintage/256/Type-icon.png
I tried to get from the class method the Uri and use it for setting up the ImageView called Image in my viewholder
viewHolder.Image.setImageURI(item.getImage());
but it didn't work, so I tried something more complex without success
//Image
URL url = null;
try {
url = new URL(item.getImage().toString());
} catch (MalformedURLException e) {
e.printStackTrace();
}
Bitmap bmp = null;
try {
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
viewHolder.Image.setImageBitmap(bmp);
} catch (IOException e) {
e.printStackTrace();
}
I have allowed internet permissions, and if I use some images from local with Uri.parse it works without any problem.
Here's the error I get from logcat
E/AndroidRuntime: java.lang.NullPointerException: Attempt to invoke virtual method 'java.net.URLConnection java.net.URL.openConnection()' on a null object reference
I think the problem is something in the url definiton but I'll ask you if someone had my same problem and how you solved. Thanks in advance!
for this purpose try to use a specific image library like Picasso, Glide or Fresco. The first one is the simplest with nice fluent interface and it loads images pretty fast:
Please check it, as you may don't know it. Here is a short description taken from its official site (link below):
Images add much-needed context and visual flair to Android
applications. Picasso allows for hassle-free image loading in your
application—often in one line of code!
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Many common pitfalls of image loading on Android are handled
automatically by Picasso:
Handling ImageView recycling and download cancelation in an adapter.
Complex image transformations with minimal memory use.
Automatic memory and disk caching.
From: http://square.github.io/picasso/
As it already Open Source project you can check the code to improve it or make your own version fitted to your actual needs.
Hope it help
In all likelihood, url = new URL(item.getImage().toString()); is throwing a MalformedURLException, which your catch block is suppressing. As a result, url is null, which is why you're getting a NullPointerException. A constructor can't return a null, so this is the only thing I can imagine.
Unless you really know what you're doing, I recommend you use a library like Glide to do image fetching.

Get scaled Image from URL

I am using the following method to get an image from a given URL.
protected Bitmap doInBackground(String... urls) {
String urlDisplay = urls[0];
Bitmap scaledImage = null;
try {
InputStream in = new java.net.URL(urlDisplay).openStream();
scaledImage = Bitmap.createScaledBitmap(BitmapFactory.decodeStream(in), 380, 250, false);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return scaledImage;
}
Is there anyway to get a scaled image without having to download the full sized image first? It would greatly increase load times.
Sadly, server side manipulations can't be done and before downloading, there's no way to scale it. However, if you still want to save the load time on consecutive refreshes, then you probably can go ahead with saving the bitmap received in a shared preference. This way if the image is already stored in the shared preference, you don't need to download it again and apply scaling to it.
CAUTION: In case the image you are downloading is changing after a while, you can put a check to download it after every "n" (say 7) days and replace the existing stored image with this one.
NOTE: Though there are many answers already available which tells you how to store the image bitmap in Shared Preference / local storage, let me know in case you need that info/ code-snippet too.
You can not perform bitmap operations on a remote image without downloading it first. Therefore there is no way to do what you want to do unless the server you are getting the image from supports different image sizes or a parameter to resize it on the server side.

Using Android's System Cache

I would like to use Android's system cache when downloading images as per these previous instructions: android system cache. I was able to get the following code working but the log statements are telling me that the images are never being read from the cache.
try {
//url = new URL("http://some.url.com/retrieve_image.php?user=" + username);
URL url = new URL("http://some.url.com/prof_pics/b4fe7bdfa174ff372c9f26ce6f78f19c.png");
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Log.i("CHAT", "this is a bitmap");
current_image.setImageBitmap((Bitmap) response);
}
else {
Log.i("CHAT", "this is not a bitmap");
Log.i("CHAT", response.toString());
InputStream is = connection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
current_image.setImageBitmap(BitmapFactory.decodeStream(bis));
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
I have tried two different types of requests, one is to go through a PHP script that returns the image and another that is directly accessing the image file. I refresh the same image multiple times in a row and it never seems to get cached. For the direct image access, I get:
05-31 23:45:12.177 I/CHAT ( 2995): this is not a bitmap
05-31 23:45:12.177 I/CHAT ( 2995): org.apache.harmony.luni.internal.net.www.protocol.http.FixedLengthInputStream#40c1c660`
For the indirect image access, I consistently get:
05-31 23:45:14.550 I/CHAT ( 2995): this is not a bitmap
05-31 23:45:14.550 I/CHAT ( 2995): org.apache.harmony.luni.internal.net.www.protocol.http.ChunkedInputStream#40c02448
I found a better way to do it. If anyone else is having trouble after following the link android system cache, use this Google developer's blog post instead. The source code in that blog post is designed for a ListView but I am using it for all image retrievals. It downloads the image in an AsyncTask, puts a temporary image while downloading, and has an image cache. This last part is listed as a "Future Item" in the blog post, but if you download the source code, the cache is implemented. I had to modify the code slightly because the AndroidHttpClient isn't supported in 2.1. I switched it to a URL connection. So far, this looks to be a great image downloader class. Let's just hope it doesn't impact our already struggling memory management issues.

how to load internet images in gridview efficiently?

I am using following example to display internet images in my activity.
http://developer.android.com/resources/tutorials/views/hello-gridview.html
In custom image adapter I'm directly loading images from internet and assigning it to imageview.
Which shows images in gridview and every thing works fine but it is not efficient way.
When ever i scroll gridview it again and again loads images and thats why gridview scrolls very slow
Is there caching or some useful technique available to make it faster?
Create a global and static method which returns a Bitmap. This method will take parameters: context,imageUrl, and imageName.
in the method:
check if the file already exists in the cache. if it does, return the bitmap
if(new File(context.getCacheDir(), imageName).exists())
return BitmapFactory.decodeFile(new File(context.getCacheDir(), imageName).getPath());
otherwise you must load the image from the web, and save it to the cache:
image = BitmapFactory.decodeStream(HttpClient.fetchInputStream(imageUrl));
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File(context.getCacheDir(), imageName));
}
//this should never happen
catch(FileNotFoundException e) {
if(Constants.LOGGING)
Log.e(TAG, e.toString(), e);
}
//if the file couldn't be saved
if(!image.compress(Bitmap.CompressFormat.JPEG, 100, fos)) {
Log.e(TAG, "The image could not be saved: " + imageName + " - " + imageUrl);
image = BitmapFactory.decodeResource(context.getResources(), R.drawable.default_cached_image);
}
fos.flush();
fos.close();
return image;
preload a Vector<SoftReference<Bitmap>> object with all of the bitmaps using the method above in an AsyncTask class, and also another List holding a Map of imageUrls and imageNames(for later access when you need to reload an image), then set your GridView adapter.
i recommend using an array of SoftReferences to reduce the amount of memory used. if you have a huge array of bitmaps you're likely to run into memory problems.
so in your getView method, you may have something like(where icons is a Vector holding type SoftReference<Bitmap>:
myImageView.setImageBitmap(icons.get(position).get());
you would need to do a check:
if(icons.get(position).get() == null) {
myImageView.setImageBitmap(defaultBitmap);
new ReloadImageTask(context).execute(position);
}
in the ReloadImageTask AsyncTask class, simply call the global method created from above with the correct params, then notifyDataSetChanged in onPostExecute
some additional work may need to be done to ensure you don't start this AsyncTask when it is already running for a particular item
You will need to implement the caching yourself. Create a proxy class that will download the images. In the getView ask this class to download an image by passing a url. In the proxy class create a HashMap that will map a url to a Bitmap. If the key for the passed url doesn't exist, download the image and store it. Otherwise returned the stored bitmap converted to an imageView.
Of course you can't afford to store as many images as you like. You need to set a limit, for example 10 images, based on the image size you expect to have. When the limit is exceeded, you need to discard old images in the favor of new ones.
You could try DroidFu. My app uses the ImageCache. There's also some manner of web-based imageview or something of the sort in the library. See in particular WebImageView and WebGalleryAdapter: http://mttkay.github.com/droid-fu/index-all.html
Edited to add: The droid-fu project is deprecated in favor of Ignition. https://github.com/mttkay/ignition

Categories

Resources