I need to loop the image load Google map marker with images. So, I am using custom marker( there will more than 50 different marker images). I am using Universal Image loader for loading the image on Image view. Once the image is loaded on the Image view I am converting that view into marker.
My problem is ImageLoadingListener is not getting looped. But if I am placing the breakpoint then It is working fine.
final View marker = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.custom_marker_layout, null);
final RoundedImageView imv_Logo = (RoundedImageView) marker.findViewById(R.id.imv_size);
bitmapArray.clear();
for (int i = 0; i < list_image_url.size(); i++) {
imageLoader.displayImage(list_image_url.get(i), imv_Logo, options,
new ImageLoadingListener() {
#Override
public void onLoadingStarted(String arg0, View arg1) {
}
#Override
public void onLoadingFailed(String arg0, View arg1,
FailReason arg2) {
imv_Logo.setImageDrawable(getResources().getDrawable(R.drawable.image_not_found));
bitmapArray.add(createDrawableFromView(Establishment.this, marker));
if (bitmapArray.size() == list_image_url.size()) {
loadmarker(progressDialog);
}
}
#Override
public void onLoadingComplete(String arg0, View arg1,
Bitmap arg2) {
bitmapArray.add(createDrawableFromView(Establishment.this, marker));
if (bitmapArray.size() == list_image_url.size()) {
loadmarker(progressDialog);
}
}
#Override
public void onLoadingCancelled(String arg0, View arg1) {
}
});
}
Could any one help me on this?
I can't guarantee it, but I guess the problem is the following. When you tell the ImageLoader to load an image into an ImageView, it will keep an internal HashMap to track which image will be displayed in which ImageView. What you are actually doing here, is asking the ImageLoader to download different images but to display them in the same ImageView.
imageLoader.displayImage(list_image_url.get(i), imv_Logo,....
So each time you call displayImage, it will actually update the Map and I guess that ImageLoader is smart enough to cancel previous downloads. So in the end, you only download one image.
While in debug mode, the download will have time to occur between twi calls to displayImage, therefore you will see multiple calls to onLoadingComplete.
What would make sense is to have several ImageViews.
Related
Iam getting some image URLs in my JSON which I parse and show in my image view. So if the Url is null, I show a default image. But in some cases the Urls are specified but the images are corrupted. In this case nothing displays in the ImageView only a white space shows. Is there any way I can handle this scenario.
Any help will be useful.
You can use ImageLoader to check this case. Example:
private ImageLoader imageLoader = new ImageLoader();
private ImageView Iv;
private String URL =null;
private DisplayImageOptions mDio;
URL = "URL you get from your JSON";
if (URL != null) {
imageLoader.displayImage(URL, Iv, mDio, new SimpleImageLoadingListener() {
#Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
// check corrupt images on here
view.setImageResource(R.drawable.iv_fail)
}
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
if (loadedImage != null) {
view.setImageBitmap(loadedImage);
}
}
}, new ImageLoadingProgressListener() {
#Override
public void onProgressUpdate(String imageUri, View view, int current,
int total) {
}
});
} else Iv.setImageResource(R.drawable.iv_default);
Hope this helps
Use picasso bro
A very easy image handling library for android
Picasso supports both download and error placeholders as optional features.
Picasso.with(context)
.load(url)
.placeholder(R.drawable.user_placeholder)
.error(R.drawable.user_placeholder_error)
.into(imageView);
http://square.github.io/picasso/
and yes,its that easy
The Best way to do it easily is to use proper lib - Use picasso or UIL or something else. Advantages is that this libs are well maintained and is stable. Your empty image will be treated as an error and default will be shown
I am using the Android-Universal-Image-Loader library to loading/caching remote images, and have been digging through the source for quite a while trying to find a way to retrieve the original image size (width and height) for my ImageLoadingListener.
The sample code below is just give you an idea of what I'm trying to do.
protected class ViaImageLoadingListener implements ImageLoadingListener {
final SelectableImageView selectableImageView ;
protected ViaImageLoadingListener(SelectableImageView selectableImageView) {
this.selectableImageView = selectableImageView;
}
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
selectableImageView.setImageBitmap(loadedImage);
// loadedImage.getWeight() will not return the original
// dimensions of the image if it has been scaled down
selectableImageView.setOriginalImageSize(width, height);
selectableImageView.invalidate();
}
I have tried extending the ImageDecoder class and the ImageLoader class to find a round-about way to linking the decoder (from which I can get the original image size in the #prepareDecodingOptions method) to my custom ImageLoadingListener. But the configuration object is private and the fields (including the decoder) are inaccessible from subclasses (and feels like an overly hacky way of solving the problem anyways).
Have I overlooked a simple "built-in" way of getting the original image size without losing the benefit of the UIL's scaling/memory management?
There is no way to pass original image size from ImageDecoder to listener through params.
I think the solution for you is following.
Extend BaseImageDecoder and create map in it for keeping image sizes:
Map<String, ImageSize> urlToSizeMap = new ConcurrentHashMap<String, ImageSize>();
Then override defineImageSizeAndRotation(...):
protected ImageFileInfo defineImageSizeAndRotation(InputStream imageStream, String imageUri) throws IOException {
ImageFileInfo info = super.defineImageSizeAndRotation(imageStream, imageUri);
urlToSizeMap.put(imageUri, info.imageSize); // Remember original image size for image URI
return info;
}
Note: info.imageSize won't compile because imageSize isn't visible. I'll fix it in next version (1.8.5) but you can use reflection for now.
Set this decoder into configuration and keep reference to this decoder anywhere (or you can make urlToSizeMap static to access from listener).
Then in your listener:
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
selectableImageView.setImageBitmap(loadedImage);
ImageSize imageSize = decoder.urlToSizeMap.get(imageUri);
selectableImageView.setOriginalImageSize(imageSize.getWidth(), imageSize.getHeight());
selectableImageView.invalidate();
}
It seems that you do not have to implement own ImageLoadingListener if you want to get original size of loaded image. I use loadImage method and it seems recieved bitmap has origin sizes.
UIL v1.8.6
loader.loadImage(pin_url, option, new SimpleImageLoadingListener() {
#Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
showErrorLayout();
}
#Override
public void onLoadingComplete(String imageUri, View view,
Bitmap loadedImage) {
// width - device width
// height - OpenGl maxTextureSize
if (width < loadedImage.getWidth() || height < loadedImage.getHeight()) {
// handle scaling
}
iv.setImageBitmap(loadedImage);
}
});
I'm showing list with one ImageView on every row of list.
For that, I download images from net in another AsyncTask using Drawable.createFromStream
And store them as Drawable in ArrayList which I pass to my Adapter class extending BaseAdapter class.
But the images are taken with high-resolution camera, so may be of very large size.
And I'm getting OutOfMemory error.
So my questions :
What is more efficient, storing images as drawable or as bitmap or any other format?
Am I doing right, by storing all images in memory(in array list). i.e. I'm thinking, once I get a image, I will show it on ImageView and will not store in ArrayList.
is there any way, I can compress the images after download, so they will take less space in memory.
My total code is present here
Android documentation provides a very good example showing how to handle bitmaps in your android app. The example uses an on-disk and in-memory cache and loads the images in the background. By doing so, the main UI thread is not slowed down by loading the images.
Loading Bitmaps effectively
In the example the images are loaded from picasa. It's easy, however, to adapt the example, so that pictures stored locally are used. You simply have to write your own ImageLoader extending from the 'ImageResizer':
public class ImageLoader extends ImageResizer {
public ImageLoader(Context context, int imageWidth, int imageHeight) {
super(context, imageWidth, imageHeight);
}
public ImageLoader(Context context, int imageSize) {
super(context, imageSize);
}
#Override
protected Bitmap processBitmap(Object data) {
return decodeSampledBitmapFromFile((String)data, imageWidth, imageHeight);
}
}
But to answer your question directly: it's ok to load images as Bitmaps. But you have to use a cache and weak references, so that the images can be garbage collected in case they are not visible on the screen. Caching them and using a background task for loading allows for a slick UI.
I don't see any efficiency in storing high-density images into memory - it's totally not recommended to store large ammount of images as bitmaps in memory (good for you that you have a good device ;))
See p.1
Try downscaling the images to fit the device's needs - that's not a simple job though. Also, see View.setTag(Object tag)
The adapter
public class MyImageListAdapter extends BaseAdapter implements ImageLoadingNotifier {
private LayoutInflater inflater = null;
public MyImageListAdapter() {
inflater = LayoutInflater)HomeActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return listImageInfo.size();
}
public Object getItem(int position) {
return listImageInfo.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (convertView == null) {
vi = inflater.inflate(R.layout.list_row, null);
}
TextView tvName = (TextView) vi.findViewById(R.id.tv_name);
TextView tvTime = (TextView) vi.findViewById(R.id.tv_time);
ImageView image = (ImageView) vi.findViewById(R.id.iv_image);
final Button btnDelete = (Button) vi.findViewById(R.id.btn_delete);
image.setImageDrawable(R.drawable.default_placeholder);//set default place-holder
new GetDrawableFromUrl(listImageInfo.get(position), vi).execute();
tvName.setText("Name: " + listImageInfo.get(position).getImage_name());
tvTime.setText("Date: " + listImageInfo.get(position).getDate_created());
btnDelete.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
final int position = listView.getPositionForView((View) v.getParent());
positionOgBtnToDelete = position;
Log.v("delete btn clicked", "delete btn no: " + position);
Toast.makeText(HomeActivity.this, "Btn delete position: " + position, Toast.LENGTH_LONG).show();
showAlertToConfirmDelete();
}
});
return vi;
}
}
The AsyncTask GetDrawableFromUrl
public class GetDrawableFromUrl extends AsyncTask<Void, Void, Drawable> {
public ImageInfo imageInfoObj;
private ImageView view;
GetDrawableFromUrl(ImageInfo imageInfo, ImageView view) {
imageInfoObj = imageInfo;
this.view = view;
}
#Override
protected Drawable doInBackground(Void... params) {
try {
return Drawable.createFromStream(((java.io.InputStream) new java.net.URL(imageInfoObj.getImageUrl()).getContent()), "src_name");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Drawable drawable) {
if (drawable != null) {
//imageInfoObj.setImage(drawable);
this.view.setImageDrawable(drawable);
//listImageInfo.add(imageInfoObj); //this one is called when the json is parsed
showImagesInList(); //don't know what it does (??)
}
}
}
The JSON parsing
JSONArray jsonArray = jsonObj.getJSONArray("result");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObjInner = jsonArray.getJSONObject(i);
ImageInfo imageInfo = new ImageInfo();
imageInfo.setImageUrl("http://www.dvimaytech.com/markphoto/" + jsonObjInner.getString("image"));
//new GetDrawableFromUrl(imageInfo).execute(); //don't needed here
imageInfo.setEmail(jsonObjInner.getString("emailid"));
imageInfo.setImage_id(jsonObjInner.getString("image_id"));
imageInfo.setImage_name(jsonObjInner.getString("image_name"));
imageInfo.setAmount(jsonObjInner.getString("amount"));
imageInfo.setImage_description(jsonObjInner.getString("image_description"));
imageInfo.setDate_created(jsonObjInner.getString("date_created"));
listImageInfo.add(imageInfo);
}
And, the use of any kind of List of images becomes unnecesary :)
Instead of starting the async task (GetDrawableFromUrl) when parsing the json objects, you can start the task in getView(...) method. This way you will not be constrained to store the drawables into that ArrayList, since you'll be modifying the ImageView after the image was downloaded. And, by default, you can put a placeholder, until the image is downloaded (or in case there are some network errors).
This way the images will start downloading only when the getView method will be called for that specific item.
The bottom line is that each view from the ListView will keep a reference to it's specific drawable (that was set using vi.setTag(image).
If this helps somehow, you know what to do ;)
There is pretty good library calling AQuery. YOu can use it and simple get all stuff like memory and file caching by writting only 2 line of code. So you even wouldn't need to prepare a drawable, you can call it directly from Adapter.getView() callback.
AQuery aq = new AQuery(rowView);
aq.id(R.id.image).image(url, false, true);
Hope it help you!
From AQuery docs:
Down Sampling (handling huge images)
We are loading a huge image from the network, but we only need the image to be bigger than 200 pixels wide. Passing in the target width of 200 will down sample the image to conserve memory.Aquery will only down sample with power of 2 (2,4,8...) for good image quality and
efficiency.The resulting image width will be between 200 and 399 pixels
String imageUrl = "http://farm6.static.flickr.com/5035/5802797131_a729dac808_b.jpg";
aq.id(R.id.image1).image(imageUrl, true, true, 200, 0);
I am making the same activity as in android to set the wallpaper from the given gallery.
I have a gallery with 50 images when gallery stop scrolling a center image comes i want to show that image in imageview.
g.setOnItemSelectedListener(new OnItemSelectedListener()
{
public void onItemSelected(AdapterView<?> arg0, View arg1,
final int arg2, long arg3)
{
imageView.setImageResource(mImageIds[arg2]);
}
public void onNothingSelected(AdapterView<?> arg0)
{
Toast.makeText(WallpaperThemeChoose.this, "NOTHING",
Toast.LENGTH_SHORT).show();
}
});
while scrolling the imageview set every image which are passing in gallery. So pause for sometime and then start i mean it stick for sometime while scrolling
I don't want to show all images which are passing but only that image which comes to center when scrolling stop.
Got the solution by setting g.setCallbackDuringFling(false);
Without starting from the middle of the stack of images how do I rotate them in the infinite loop left to right and right to left? I tried setSelection(position) but for some reason I get that method called few times and inconsistently. My images increment has to be saved int he app state so it makes it a bit more complicated.
#Override
public void setSelection(int position){
int sectionPos = getCurrentPositionFromState();
if (sectionPos == (this._images - 1)){
setCurrentPositionFromState(0);
sectionPos = 0;
}
else {
setCurrentPositionInState(sectionPos +1);
}
if (sectionPos <= (this._images - 1) ){
super.setSelection(sectionPos);
}
}
gallery.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView parent, View view, int position, long id) {
gallery.setSelection(position);
#Override
public void onNothingSelected(AdapterView parent) {
}
});
I should also mention that I have an onFling() overriden like so:
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return super.onFling(e1, e2, 0, velocityY);
}
There are a few ways to go about it, but in all cases, it's never technically "infinite." I got the basis of mine from snooping around for a while.
First we need to put a gallery into the xml file in the layout. So after creating the file put in a little snippet like this:
<!-- Gallery To show images Gallery -->
< Gallery
android:id="#+id/galleryView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingBottom="15dip"/>
Now lets set up a Vector of different images so we can loop through. We will be getting these images from our resources, but if you want to get them from somewhere else then just insert that instead. We are going to insert this into onCreate(). This will allow us to have a vector of id's that we can reference when getting images to put into the gallery later:
public Vector<Integer> mPhotoVector = new Vector<Integer>();
public void setPhotos() {
for(as many photos as you want){
int imageResource = getResources().getIdentifier("imageNAme", "drawable", getPackageName());
mPhotoVector.add(imageResource);
}
Where galView is my gallery view from the layout. And as we finish up this project we need to call the gallery view from the xml and initialize it to a gallery variable we will have in the code.
LoopingGalleryAdapter adapter;
Gallery galView;
adapter = new LoopingGalleryAdapter(this, mPhotoVector);
galView = (LoopingGallery)mLayoutView.findViewById(R.id.galleryView);
galView.setAdapter(adapter);
galView.setSelection((galView.getCount() / 2));
The setSelection() will have us looking at the middle of the gallery, this makes it appear to be "infinite" since there are now 1073741823 elements to each side.
Next we need to create the adapter. The basis is to make the largest gallery you can, so next we just add in our own little getCount method. This will create a gallery that is too large for the user to (plausibly) scroll to the end of.
Lastly on the adapter we have the meat of the project which requires us to set where our position is. This is the key. Once the position is set to the middle-ish of the gallery, it seems as though you have an infinite loop of images on either side.
I started mine off a little like this:
public class LoopingGalleryAdapter extends BaseAdapter {
private ImageView iv;
private Context mContext;
public PhotoVector mPhotoVector = null;
int mGalleryItemBackground;
public LoopingGalleryAdapter(Context c, PhotoVector aVector) {
this.mContext = c;
mPhotoVector = aVector;
}
public int getCount() {
return Integer.MAX_VALUE;
}
#Override
public Object getItem(int position) {
return position;
}
public ImageView getImage(){
return iv;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
iv = new ImageView(mContext);
private final int middle = 1073741823; //this is the middle index of the gallery in galView
/************************************************************************
*if you have a vector/array/arrayList of photos you would like to display
************************************************************************/
if((position - middle) >= 0) { relativePosition = (position-middle) % mPhotoVector.size(); }
else { relativePosition = mPhotoVector.size() - (Math.abs(position - middle) % mPhotoVector.size()); }
Drawable draw = mContext.getResources().getDrawable(mPhotoVector.get(relativePosistion));
/*********************************************
*otherwise you can just insert a photo like so
*********************************************/
Drawable draw = mContext.getResources().getDrawable(R.drawable.what_you_want);
iv.setImageDrawable(draw);
return iv;
}
}
And we are now done!
Additionally, one of the tricks I have found quite useful, if not necessary when getting images from the internet is to keep a count of how many times you have gone through getView() and after 10-20 times clear your cache so you don't throw a OutOfMemoryError by doing:
if(counter >= 20){
galView.destroyDrawingCache();
counter = 0;
}
Or have getView() throw a OutOfMemoryError, catch it and return an empty ImageView (iv) and then clear then call galView.destroyDrawingCache();
A shameless self plug, just wrote an Infinite Scrolling Gallery tutorial:
http://blog.blundellapps.com/infinite-scrolling-gallery/
Source code can be downloaded also, you choose the image size.
You can use images on your SD card or images in your /resources/drawable directory.