In my project, I have to display both remote and local images. I can display remote images using Volley NetworkImageView.
NetworkImageView networkImgVw = (NetworkImageView)rootView.findViewById(R.id.niv);
networkImgVw.setImageUrl(url, imageLoader);
However, I fail to use NetworkImageView to display local images.
Bitmap bitmap = BitmapFactory.decodeFile(path, bmOptions);
coverImgVw.setImageBitmap(bitmap);
Does anybody have a solution to this problem ?
I have figured it out. I put the solution here in case that anyone has the same problem.
Inside the NetworkImageView.java, I just change as follows:
private void loadImageIfNecessary(final boolean isInLayoutPass) {
...
if (TextUtils.isEmpty(mUrl)) {
if (mImageContainer != null) {
mImageContainer.cancelRequest();
mImageContainer = null;
}
//setImageBitmap(null); comment out this line
return;
}
}
Related
I am learning Android dev. and am developping a Hearthstone app using a Hearthstone API for fun.
My users can search for specific cards and now I wish to implement a Card Displayer that displays cards by their type, and lets the user swipe right or left to display the next one in my JSONArray. My API request gives me one and each JSONObject has an img attribute with the cards image URL.
Therefore, when the user swipes I am doing the following:
// Swipe right -> number - 1 (Previous page)
// Swipe left -> number + 1 (Next page)
public void displayCardNumber(int number) {
APIRequests apiRequests = new APIRequests();
try {
// Gets the JSONObject at 'number' and retrieves its img URL.
JSONObject card = (JSONObject) cardsArray.get(number);
String currentImageURL = (String) card.get("img");
// Here is where my problem is.
Bitmap bitmap = apiRequests.getImageBitmap(currentImageURL);
if (bitmap != null) {
setNewImage(bitmap);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
But apiRequest.getImageBitmap(URL) is where I have a problem.
I must download the image in order to display it, but not only does the following block of code not work when I download more than one image, I must also find an efficient way of displaying my cards (that requires background download perhaps?).
// Returns the image's bitmap using the URL
protected Bitmap getImageBitmap(String currentImageURL) {
try {
Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(currentImageURL).getContent());
return bitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
Why can't I download more than 1 image? Is my way of getting my Bitmap false?
Thank you.
Use Glide https://github.com/bumptech/glide .This is faster.
Bitmap theBitmap = Glide.
with(this).
load(imgUrl). //image url as string
asBitmap().
into(100, 100). // Width and height
get();
You can also use it with another way like this:
Glide.with(context).load(url) // image url
.thumbnail(0.5f)
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(imgId) // If no image found the imgId is the default image id for the imageView
.into(imageView); // imageView to show the image
I have found a solution,
In order to load my image and display it I now use a library called Android Universal Image Loader that lets me do the following:
// Load image, decode it to Bitmap and display Bitmap in ImageView
ImageLoader imageLoader = ImageLoader.getInstance();
ImageView i = (ImageView)view.findViewById(R.id.cardDisplay);
imageLoader.displayImage(currentImageURL, i);
I retrieve the correct URL in my AsyncTask's doInBackground and display it with the library's method.
Question 1: Is it possible to download image file without giving the reference to ImageView?
Question 2: Can i download each file in a separage instance of aQuery or do i have to download the file sequentially? e.g, waiting for the callback of current file download and then trigger the next file download call? Below is my code
// Ad is my custom model class
// adList is my list of Ads having URL's to the ads hosted somewhere
// imageView is an invisible imageView as downloading does not start if i don't give any reference to any imageView resource
for (String adUrl : adList) {
if (adUrl.length() > 0) {
AQuery aQuery = new AQuery(DownloadAdActivity.this);
BitmapAjaxCallback callback = new BitmapAjaxCallback();
callBack.url(adUrl);
callBack.fallback(R.id.placeHolderResource);
callBack.fileCache(true);
callBack.memCache(true);
aQuery.id(imageView).image(callBack);
}
}
I need to download 20/30 images when the app starts first time, so far i am doing it by giving a hidden imageView reference and trigging the aQuery sequentially after each image has downloaded. I tried to generate 20/30 request in a loop but only the last aQuery trigger call works which cancels the previous image download call.
Please guide me:
1- How to cache images without giving any reference to the imageView
2- How to download images in parallel manner, not in sequential manner through AQuery.
1) You can use ajax call without ImageView reference to download image.
androidQuery.ajax("url", Bitmap.class, 0, new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap bitmap, AjaxStatus status) {
super.callback(url, bitmap, status);
}
});
2) By default you can download 4 images concurrently. But you can change as per your requirement like this
AjaxCallback.setNetworkLimit(8);
You can use Picasso
It will make all the downloads and also the caching for the images.
Anyway if the images are quite small you should prepare a "zip" file and dl all of them with an AsyncTask / Thread and unzip them. Opening and closing the connections to the server are "very expensive" operations in time consuming.
Here is method to obtain bitmap from url using AQuery
static Bitmap myBitmap = null;
public static Bitmap getBitmapFromURL(String src) {
try {
Log.i(TAG, "Image Url is : " + src);
AQuery androidQuery = new AQuery(ChatApplication.getInstance());
androidQuery.ajax(src, Bitmap.class, 0, new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap bitmap, AjaxStatus status) {
super.callback(url, bitmap, status);
if (bitmap != null)
myBitmap = bitmap;
}
});
} catch (Exception e) {
Log.i(TAG, "Error due to " + e);
}
return myBitmap;
}
AQuery aq = new AQuery(context);
aq.ajax(url_of_image, Bitmap.class, new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap object, AjaxStatus status) {
}
});
Im sorry for replying late,But this is best library I have ever came across.
Yes,You can download. Bitmap object will give you the image.
You can create multiple instances of Aquery if you want to download or pass the each URL after one download finishes,you can use any loop for that.
I'm using ION (https://github.com/koush/ion) to load images from the web into a ListView of ImageView. Currently I want to get the bitmap from the ImageView, but I'm getting one exception that is force closing my app:
java.lang.ClassCastException: com.koushikdutta.ion.IonDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
These are the lines that I'm using:
final ImageView itemImageView = (ImageView)view.findViewById(R.id.photoImage);
final Bitmap itemDrawable = ((BitmapDrawable) itemImageView.getDrawable()).getBitmap();
How can I solve this? Thanks in advance!
Ion sets a custom drawable to manage animated GIFs, fade transitions, etc, so it can't be cast to a BitmapDrawable.
Use:
Ion.with(imageView).getBitmap()
to get the bitmap out
If you set a callback when making the Ion request and have it return an ImageViewBitmapInfo you can retrieve bitmaps that way. For e.g.
Ion.with(imageView)
.placeholder(R.drawable.default_avatar)
.load(userImageURL)
.withBitmapInfo()
.setCallback(new FutureCallback<ImageViewBitmapInfo>() {
#Override
public void onCompleted(Exception e, ImageViewBitmapInfo result) {
// Check for exceptions
// Check bitmaps first
Bitmap b = result.getBitmapInfo().bitmaps[0];
...
};
It may be worth looking into:
nostra13's "Universal Image Loader"
It's an awesome library with tons of features to display images from URLs, cast to bitmaps, etc.
if(imageView.getDrawable() instanceof BitmapDrawable)
bm = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
else { /***to check if it is ION drawable, use ION*/
bm = Ion.with(imageView).getBitmap();
}
I have an Image on my server. The URL for the image is something like:
http://www.mydomain.com/123456uploaded_image.jpg
I am trying to set this image to my ImageView. Here is the code that I tried:
try{
String url1 = myeventimagearray[position];
URL ulrn = new URL(url1);
HttpURLConnection con = (HttpURLConnection)ulrn.openConnection();
InputStream is = (InputStream) con.getInputStream();
Bitmap bmp = BitmapFactory.decodeStream(is);
if (null != bmp)
iveventimg.setImageBitmap(bmp);
else
Log.i("Image","Not set");
} catch(Exception e) {
e.printStackTrace();
}
When I try this, my imageview is empty, i.e., it doesn't set the image view and i get this System err in my logcat:
java.lang.ClassCastException: libcore.net.http.FixedLengthInputStream cannot be cast to com.example.eventnotifier.Base64$InputStream
Base46.java is a file I found from the internet that Encodes and decodes to and from Base64 notation.
Any idea why I'm getting this System.error?
Thank you
Use URlImageViewHelper, it will take care of loading url into imageview.
Refer this
It will take care of caching, loading in background etc. by itself.
This is not an easy answer but you should use a caching system.
See https://github.com/chrisbanes/Android-BitmapCache for an excellent one!
Simply swap the ImageView for NetworkCacheableImageView and then use loadImage( "http://....", true );
You are likely getting an exception because you are trying to do network io on the main thread. Consider using a loader or an AsyncTask to load your image.
Check your logs, I bet you are printing a stack trace in the auto generated catch block.
new Thread(new Runnable() {
public void run() {
final Bitmap b = bitmap = BitmapFactory.decodeStream((InputStream)new URL(myeventimagearray[position]).getContent());
iveventimg.post(new Runnable() {
public void run() {
iveventimg.setImageBitmap(b);
}
});
}
}).start();
Use Picasso to fetch image from url. Implement 'com.squareup.picasso:picasso:2.71828' in build.gradle and in java
Picasso.get()
.load(url) // http://www.example.com/123456uploaded_image.jpg
.resize(50, 50)
.centerCrop()
.into(imageView)
I have a scrollview which has small thumbnails of images loaded via AsyncTask and throws the image URL unto a imageView.
They are added dynamically and then on top, is a main imageView which holds the image of the thumbnail you clicked.
Everything runs great until you have about 10+ images in the thumbnails...
I am loading the mainImage url via the same way as the thumbnails, so when they click an image in the thumb, it loads it up top.
I am recycling the bitmap in the method itself, but it seems to be running out of memory and crashing when loading more than 10 images (thumbnails load ok, but crashes when i click to load the main image)
any help appreciated
this is the code i am using the load the images (thumbnails + main):
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
just implement this on ur image ... it will reduce ur image by 4 times
public static Bitmap getImage(byte[] image) {
BitmapFactory.Options config = new BitmapFactory.Options();
config.inPreferredConfig = Bitmap.Config.RGB_565;
config.inSampleSize = 4;
return BitmapFactory.decodeByteArray(image, 0, image.length,config);
}
You should read the two following Android official tutorials. They will teach you how to load large bitmap efficiently, and they provide working code samples that we use in our production apps
Displaying Bitmaps Efficiently
Loading Large Bitmaps Efficiently
you are not closing the input stream. So all the time when images urls executed input stream objects created which are expensive and causing you OutofMemoryError. add below code after catch block.
in.close();
in = null;
You probably have to work with some sort of cache strategy for the bitmaps, try having a look on the library Universal Image Loader, it works very well for what you need
Recycling bitmaps by yourself should only be done when you know for sure that it won't be used anymore.
Try to resize the bitmap to a smaller size (with a factor like 1.5 example: width=widt*1.5)
then strech(fit xy or whatever) in your view.it will lower the quality of the image due to the factor you decide. it is a quick dirty way. also making bit map rgb like Niun Goia mentions works well.
You shouldn't be using a ScrollView for this. You should be using a ListView. When you use a ScrollView (with a LinearLayout or something like that inside it), all the elements in the list (no matter how big it is) will try to be loaded immediately. Try a ListView instead (which is made for that exact reason, it only loads in memory the ui elements of the rows that are visible).
You can use android:largeHeap="true" to request a larger heap size
answer
I use this..
Options opt = new Options();
opt.inPurgeable = true;
opt.inInputShareable = true;
opt.inPreferredConfig = Bitmap.Config.RGB_565;